웹에서 상태를 저장할 때 클라이언트(브라우저)에서는 보통 3가지의 방법이 있다.
1. 전통적인 쿠키 (도메인당 쿠키 수 제한, 용량 제한 4KB)
2. HTML5 브라우저 세션 sessionStorage(5MB 제한, 브라우저를 닫으면 지워짐)
3. HTML5 브라우저 스토리지 localStorage (5MB 제한, 따로 지우지 않는 한 계속 유지됨)
쿠키의 경우 서버측 코드로 접근이 가능하지만 2,3번은 불가능하며 별도의 작업(Header, Parameter)에 담아서 서버 측에 전송 가능하다. (쿠키는 매번 서버로 전송 된다 => 네트워크 트레픽 비용 증가)
모던한 웹 개발에선 2,3 번을 주로 권장한다.
localStorage 및 sessionStorage는 다음과 같은 차이점이 있습니다.
- localStorage는 사용자 브라우저로 범위가 지정됩니다. 사용자가 페이지를 다시 로드하거나 브라우저를 닫았다가 다시 열면 상태가 유지됩니다. 사용자가 여러 개의 브라우저 탭을 여는 경우 탭 간에 상태가 공유됩니다. 명시적으로 지울 때까지 데이터가 localStorage에 유지됩니다.
- sessionStorage는 사용자의 브라우저 탭으로 범위가 지정됩니다. 사용자가 탭을 다시 로드하면 상태가 유지됩니다. 사용자가 탭 또는 브라우저를 닫으면 상태가 손실됩니다. 사용자가 여러 개의 브라우저 탭을 여는 경우 각 탭에 독립적인 고유한 버전의 데이터가 있습니다.
일반적으로 sessionStorage를 사용하는 것이 더 안전합니다. sessionStorage를 사용하면 사용자가 여러 탭을 열 때 다음과 같은 경우가 발생하는 위험을 방지할 수 있습니다.
- 탭 간에 상태 스토리지의 버그
- 한 탭에서 다른 탭의 상태를 덮어쓸 때 혼동되는 동작
앱이 브라우저를 닫았다가 다시 열 때 상태를 유지해야 하는 경우 localStorage를 선택하는 것이 좋습니다.
브라우저 스토리지를 사용하는 경우의 주의 사항:
- 서버 쪽 데이터베이스를 사용하는 경우와 유사하게, 데이터 로드 및 저장은 비동기입니다.
- 서버 쪽 데이터베이스와 달리, 미리 렌더링 단계에서는 요청한 페이지가 브라우저에 없기 때문에 미리 렌더링하는 동안 스토리지를 사용할 수 없습니다.
- Blazor Server 앱의 경우 몇 킬로바이트의 데이터 스토리지를 유지하는 것이 좋습니다. 몇 킬로바이트를 넘을 경우, 네트워크를 통해 데이터를 로드하고 저장하기 때문에 성능에 미치는 영향을 고려해야 합니다.
- 사용자가 데이터를 보거나 조작할 수 있습니다. ASP.NET Core 데이터 보호는 위험을 완화할 수 있습니다.
public async Task InitAsync()
{
_initializing = true;
var vmJson = await _client.GetStringAsync(_config.Url);
var vm = JsonSerializer.Deserialize<HealthModel>(vmJson, _options);
_model.AgeYears = vm.AgeYears;
_model.HeightInches = vm.HeightInches;
_model.IsFemale = vm.IsFemale;
_model.IsMetric = vm.IsMetric;
_model.WeightPounds = vm.WeightPounds;
_initializing = false;
}
private async void Model_PropertyChanged(object sender,
System.ComponentModel.PropertyChangedEventArgs e)
{
if (_initializing || _config == null)
{
return;
}
var vm = JsonSerializer.Serialize(_model);
var content = new StringContent(vm);
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
await _client.PostAsync(_config.Url, content);
}
@page "/LocalStorage"
@inject NavigationManager NavigationManager
@inject Blazored.LocalStorage.ILocalStorageService localStore
@inject Blazored.SessionStorage.ISessionStorageService sessionStorage
@using Blazor.App.Tmp.Data
@using Models.Shared.Blazor
@using Models.Shared.Blazor.Validator
@inject WeatherForecastService ForecastService
<h1>Your Local Session Storage Note</h1>
<MatH3>@getLocalStorage</MatH3>
<MatH3>@getSessionStorage</MatH3>
<textarea @bind="getLocalStorage" />
<textarea @bind="getSessionStorage" />
<br />
<button @onclick="UpdateLocalStorage">Save</button>
<button @onclick="ClearLocalStorage">Clear</button>
@code {
const string noteKey = "note";
const string listKey = "lotto";
public string getLocalStorage { get; set; }
public string getSessionStorage { get; set; }
public DtoList getdtLocalStorage { get; set; }
public DtoList getdtSessionStorage { get; set; }
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
await SetessionStorage();
getLocalStorage = await localStore.GetItemAsync<string>(noteKey);
getSessionStorage = await sessionStorage.GetItemAsync<string>(noteKey);
}
}
private async Task SetessionStorage()
{
//await localStore.SetItemAsync(noteKey, "localStore");
//await sessionStorage.SetItemAsync(noteKey, "sessionStorage");
ClearLocalStorage();
await GetLocalSessionStorage();
//await localStore.GetItemAsync<string>(noteKey);
//await sessionStorage.GetItemAsync<string>(noteKey);
//await localStore.SetItemAsync(listKey, dtoList);
//await sessionStorage.SetItemAsync(listKey, dtoList);
}
private async Task GetLocalSessionStorage()
{
DtoList dtoList = await ForecastService.GetCustomers(1, 200);
foreach(var c in dtoList.Dto)
{
await localStore.SetItemAsync(string.Format("{0}_{1}", c.Id, c.Name), c.Region.ToString());
await sessionStorage.SetItemAsync(string.Format("{0}_{1}", c.Id, c.Name), c.Region.ToString());
}
foreach (var c in dtoList.Dto)
{
await localStore.SetItemAsync(string.Format("{0}_{1}_01", c.Id, c.Name), c.Region.ToString());
await sessionStorage.SetItemAsync(string.Format("{0}_{1}_01", c.Id, c.Name), c.Region.ToString());
}
foreach (var c in dtoList.Dto)
{
await localStore.SetItemAsync(string.Format("{0}_{1}_02", c.Id, c.Name), c.Region.ToString());
await sessionStorage.SetItemAsync(string.Format("{0}_{1}_02", c.Id, c.Name), c.Region.ToString());
}
foreach (var c in dtoList.Dto)
{
await localStore.SetItemAsync(string.Format("{0}_{1}_03", c.Id, c.Name), c.Region.ToString());
await sessionStorage.SetItemAsync(string.Format("{0}_{1}_03", c.Id, c.Name), c.Region.ToString());
}
foreach (var c in dtoList.Dto)
{
await localStore.SetItemAsync(string.Format("{0}_{1}_04", c.Id, c.Name), c.Region.ToString());
await sessionStorage.SetItemAsync(string.Format("{0}_{1}_04", c.Id, c.Name), c.Region.ToString());
}
foreach (var c in dtoList.Dto)
{
await localStore.SetItemAsync(string.Format("{0}_{1}_05", c.Id, c.Name), c.Region.ToString());
await sessionStorage.SetItemAsync(string.Format("{0}_{1}_05", c.Id, c.Name), c.Region.ToString());
}
foreach (var c in dtoList.Dto)
{
await localStore.SetItemAsync(string.Format("{0}_{1}_06", c.Id, c.Name), c.Region.ToString());
await sessionStorage.SetItemAsync(string.Format("{0}_{1}_06", c.Id, c.Name), c.Region.ToString());
}
foreach (var c in dtoList.Dto)
{
await localStore.SetItemAsync(string.Format("{0}_{1}_07", c.Id, c.Name), c.Region.ToString());
await sessionStorage.SetItemAsync(string.Format("{0}_{1}_07", c.Id, c.Name), c.Region.ToString());
}
}
private async Task GetSessionStorage()
{
getdtLocalStorage = await localStore.GetItemAsync<DtoList>(listKey);
getdtSessionStorage = await sessionStorage.GetItemAsync<DtoList>(listKey);
}
public async void UpdateLocalStorage()
{
await localStore.SetItemAsync(noteKey, getLocalStorage);
await sessionStorage.SetItemAsync(noteKey, getSessionStorage);
}
public async void ClearLocalStorage()
{
//getdtLocalStorage = null;
await localStore.ClearAsync();
await sessionStorage.ClearAsync();
//getdtSessionStorage = null;
//await localStore.RemoveItemAsync(noteKey);
//await sessionStorage.RemoveItemAsync(noteKey);
}
}
'워크' 카테고리의 다른 글
UserAgent 가져오기 (0) | 2020.07.17 |
---|---|
blazor Cookie (0) | 2020.07.15 |
blazor MatTab (0) | 2020.07.13 |
NavigationManager 시트 (0) | 2020.07.12 |
BlazorInputFile FileUpload (0) | 2020.07.11 |