Deep dive into browser storage
Foreword
With the development and evolution of mobile networks, in addition to native apps, we can now run "WebApps" on our mobile phones - it can be used right away, and it can be used as soon as it is used up. An excellent WebApp can even have features and experiences comparable to native apps. Part of the reason for the excellent performance of WebApp is due to the improvement of browser storage technology. The function of cookie data storage has been difficult to meet the development needs and is gradually replaced by Web Storage and IndexedDB. This article will introduce the differences, advantages and disadvantages of these storage methods.
1. Cookies
1. Origin of cookies
A cookie's job is not to store it locally, but to "maintain state" . Because the HTTP protocol is stateless, the HTTP protocol itself does not save the communication state between the request and the response. Generally speaking, the server does not know what the user did last time, which seriously hinders the realization of interactive web applications. In a typical online shopping scenario, a user browses several pages and buys a box of cookies and two bottles of drinks. At the final checkout, due to the stateless nature of HTTP, the server does not know what the user bought without additional means, so the cookie was born. It is one of the "extras" used to circumvent HTTP's statelessness. The server can set or read the information contained in the cookie, thereby maintaining state in the user's session with the server.
In the shopping scene just now, when the user purchases the first item, the server sends a cookie to record the information of that item while sending the web page to the user. When the user visits another page, the browser sends the cookie to the server, so the server knows what he has purchased before. The user continues to buy drinks, and the server adds new product information to the original cookie. At checkout, the server just reads the cookie sent.
2. What is a cookie
A cookie refers to data (usually encrypted) that some websites store on a user's local terminal in order to identify the user. Cookies are generated by the server, maintained and stored by the client, and stored in memory or disk. Through the cookie, the server can know which client the request is from and can maintain the client state. For example, after logging in and refreshing, the request header will carry the Set-Cookie in the response header at the time of login, and the Web server will also receive the request. The value of the cookie can be read out, and the information status of some users can be judged and restored according to the content of the cookie value.
In short, cookies make it possible to record stable state information based on the stateless HTTP protocol.
Cookies are mainly used for the following three aspects:
- Session state management (such as user login status, shopping cart, game score or other information that needs to be recorded)
- Personalization settings (such as user-defined settings, themes, etc.)
- Browser behavior tracking (such as tracking and analyzing user behavior, etc.)
3. The principle and composition of cookies
When visiting the website for the first time, the browser sends a request, the server generates a cookie and informs the client through the Set-Cookie header in the response (multiple values are allowed in the Set-Cookie header). After the client gets the cookie, Subsequent requests will automatically carry the cookie header into the request and send it to the server (see the example below). In addition, the expiration time, domain, path, validity period, and applicable site of the cookie can be specified as needed.
HTTP/1.1 200 OK
Content-type: text/html
Set-Cookie: name=value
Other-header: other-header-value
This HTTP response will set a cookie named "name" with a value of "value". Both names and values are URL encoded when sent. The browser will store this session information and send it back to the server on each subsequent request via the HTTP header cookie, for example:
GET /index.jsl HTTP/1.1
Cookie: name=value
Other-header: other-header-value
A cookie is made up of the following parameters in the browser:
- name: A name that uniquely identifies the cookie. Cookie names are not case sensitive, so myCookie and MyCookie are the same name. In practice, however, it is best to treat cookie names as case-sensitive, as some server software may treat them that way. The cookie name must be URL encoded.
- value: The string value stored in the cookie. This value must be URL encoded.
- Domain: The domain for which the cookie is valid. All requests sent to this domain will contain the corresponding cookie. If not specified, the default is the document source (defined by the protocol, domain name and port), excluding subdomain names. If specified Domain, subdomains are normally included. Therefore, specifying Domain it is less restrictive than omitting it. However, this can be helpful when subdomains need to share information about users. For example, if Domain=mozilla.org is set, cookies are also included in subdomains (e.g., developer.mozilla.org).
- Path: This path is included in the request URL to send the cookie to the server.
/docs
/docs/Web/
/docs/Web/HTTP
- Expires/Max-Age: Set the cookie expiration time (Expires) or validity period (Max-Age) (that is, after what time it will not be sent to the server). A cookie in the form of a simple name/value pair exists only for the duration of the current session and is lost when the user closes the browser. If you want the cookie lifetime to exceed a single browsing session, specify Expires/Max-Age, max-age takes precedence over expires.
- Secure: When set, the cookie will only be sent to the server if an SSL secure connection is used. For example, requests https://www.rendc.com send cookies, while requests http://www.rendc.com do not.
- HttpOnly : Cookies with the HttpOnly attribute set cannot be accessed using JavaScript via the Document.cookie attribute, XMLHttpRequest and Request APIs to prevent cross-site scripting (XSS).
HTTP/1.1 200 OK
Content-type: text/html
Set-Cookie: name=value; domain=.rendc.com; path=/; secure
Other-header: other-header-value
The cookie created here is valid for all subdomains of wrox.com and all pages in that domain (specified by path=/). However, this cookie can only be sent over an SSL connection because the secure flag is set.
Be aware that the domain, path, expiration and secure flags are used to tell the browser when the cookie should be included in the request. These parameters are not sent to the server with the request, only the cookie name/value pair is actually sent.
4. Cookies in JavaScript
There are two main ways to generate cookies. One is to inform the client through the Set-Cookie header in the response mentioned above; the other is to read and write cookies through document.cookie in JavaScript. ,as follows:
console.log(document.cookie);
document.cookie='myname=rendc;path=/;domain=.rendc.com';
Handling cookies in JavaScript is more troublesome, because the interface is too simple, only the document.cookie property of the BOM. When setting the value, a new cookie string can be set via the document.cookie property. This string is added to the original cookie after it is parsed. Setting document.cookie will not overwrite any previously existing cookies unless an existing cookie is set. To specify additional information for the created cookie, simply append a string of the same format directly after the Set-Cookie header:
document.cookie = encodeURIComponent("name") + "=" +
encodeURIComponent("rendc") + "; domain=.rendc.com; path=/";
5. Defects of cookies
- The cookie is not big enough
- The size of each cookie is 4KB (the name and value are included in this 4KB ), which is not enough for complex storage requirements. When the cookie exceeds 4KB, it will face the fate of being cut off. In this way, cookies can only be used to access a small amount of information. In addition, many browsers also limit the number of cookies on a site (generally no more than 300 cookies).
- Too many cookies can lead to huge performance waste
Cookies are tied to a specific domain. All requests under the same domain name will carry cookies. Just imagine, if we just request a picture or a CSS file at the moment, we also have to run around with a cookie (the key is that the information stored in the cookie is not needed), this is a labor-intensive thing. Although the cookie is small, with the stacking of requests, the overhead brought by such unnecessary cookies will be unimaginable.
Cookies are used to maintain user information, and all requests under the domain name (domain) will carry cookies, but for static file requests, carrying cookie information is useless at all. The domain name of the site is resolved separately.
- Since cookies in HTTP requests are passed in clear text, security is a problem unless HTTPS is used.
6. Cookies and Security
There are two ways to ensure that cookies are sent securely and cannot be accessed by unintended actors or scripts: Secure attributes and HttpOnly attributes.
Cookies marked as Secure should only be sent to the server through requests encrypted by the HTTPS protocol, thus preventing man-in-the-middle attacks. But even if Secure flags are set, sensitive information should not be transmitted through cookies, because cookies are inherently insecure, and Secure flags do not provide any real security guarantee that, for example, someone with access to the client's hard drive can read it.
As of Chrome 52 and Firefox 52, insecure sites (http:) cannot use the cookie Secure flag.
The JavaScript Document.cookie API cannot access cookies with HttpOnly attributes; such cookies only act on the server. For example, cookies that persist server-side sessions do not need to be available to JavaScript, but should have HttpOnly attributes. This precaution helps mitigate cross-site scripting (XSS) attacks.
Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2019 07:28:00 GMT; Secure; HttpOnly
The restrictions on cookies and their characteristics determine that cookies are not an ideal way to store large amounts of data, allowing "professional people to do professional things", and Web Storage appeared.
A new local storage solution, Web Storage, has been added to HTML5, so that with Web Storage, cookies can only do what it should do - as a channel for the client to interact with the server, keeping the client state.
2. Web Storage
The purpose of Web Storage is to solve the problem of using cookies when storing data through the client that does not need to be frequently sent back to the server. The Web Storage API contains two objects: localStorage and sessionStorage, which are essentially objectifications of mapping string keys and values. localStorage is a permanent storage mechanism, and sessionStorage is a storage mechanism across sessions. These two browser storage APIs provide two ways to store data in the browser independent of page refreshes.
1. Storage object
The localStorage and sessionStorage properties of the Window object refer to the Storage object. The Storage object is used to hold name/value pair data up to the storage limit (determined by the browser). In general, the size limit of client data is set per source (protocol, domain, and port), so each source has a fixed size of data storage space. Different browsers set different space limits for localStorage and sessionStorage, but most limit them to 5MB per source.
The Storage object defines the following methods:
- clear(): removes all values; not implemented in Firefox.
- getItem(name): Get the value of the given name.
- key(index): Get the name of the given numerical position.
- removeItem(name): removes the name/value pair of the given name.
- setItem(name, value): Sets the value of the given name.
Key-value pairs in Storage objects are always stored as strings, which means that numeric types are automatically converted to string types.
2. sessionStorage
The sessionStorage object only stores session data, which means that data will only be stored until the browser is closed. This is similar to a session cookie that disappears when the browser is closed. The data stored in sessionStorage is not affected by page refresh and can be restored after browser crash and restart (depending on browser, Firefox and WebKit support, IE does not support).
SessionStorage In particular, it should be noted that even if two pages under the same domain name, as long as they are not opened in the same browser window, their sessionStorage data cannot be shared.
LocalStorage is the same as sessionStorage in terms of API. Here we take sessionStorage as an example:
Store data: setItem()
sessionStorage.setItem('user_name', 'rendc')
Read data: getItem()
sessionStorage.getItem('user_name')
Delete the data corresponding to a key name: removeItem()
sessionStorage.removeItem('user_name')
Clear data records: clear()
sessionStorage.clear()
Although Web Storage will bring many conveniences for storing data, it also has some inconveniences in actual development:
- sessionStorage itself has an API, but it's just a simple key/value form
- sessionStorage only stores string and needs to be converted into json objects
Based on the above two points, it will be encapsulated and then called during the development process:
setItem(key,value,module_name){
if (module_name){
let val = this.getItem(module_name);
val[key] = value;
this.setItem(module_name, val);
}else{
let val = this.getStorage();
val[key] = value;
window.sessionStorage.setItem(STORAGE_KEY, JSON.stringify(val));
}
},
getItem(key,module_name){
if (module_name){
let val = this.getItem(module_name);
if(val) return val[key];
}
return this.getStorage()[key];
},
getStorage(){
return JSON.parse(window.sessionStorage.getItem(STORAGE_KEY) || '{}');
}
3. localStorage
localStorage is similar to sessionStorage, but the difference is that the data stored in localStorage can be retained for a long time; and when the page session ends (ie when the page is closed), the data stored in sessionStorage will be cleared. To access the same localStorage object, pages must come from the same domain (subdomains are not allowed) and use the same protocol on the same port.
Considering that one of the characteristics of localStorage is persistence, sometimes we prefer to use it to store some resources with stable content. For example, e-commerce websites with rich image content will use it to store image strings in Base64 format.
Some websites also use it to store some infrequently updated CSS, JS and other static resources.
4. The difference between Web Storage and cookies
Let's talk about what the two have in common first, and then elaborate on where they differ:
- Common ground: They are all saved on the browser side, and they all follow the same-origin policy.
- The difference: the difference between the life cycle and the scope
Scope: localStorage can read/modify the same localStorage data under the same protocol, same hostname, and same port. However, sessionStorage is a bit stricter than localStorage. In addition to protocol, host name, and port, it is also required to be in the same window (that is, the browser tab).
Life cycle: localStorage is a persistent local storage, the data stored in it will never expire, and the only way to make it disappear is to delete it manually; while sessionStorage is a temporary local storage, it is a session-level storage, when When the session ends (the page is closed), the stored content is also released.
After all, Web Storage is an extension of cookies, which can only be used to store a small amount of simple data. When it comes to large-scale, complex data, Web Storage is helpless. At this time, we need to know our ultimate big boss - IndexedDB!
4. IndexedDB
The Indexed Database API, referred to as IndexedDB, is a solution for storing structured data in the browser. The idea behind IndexedDB is to create an API that facilitates the storage and retrieval of JavaScript objects, while also supporting query and search.
IndexedDB is a database similar to MySQL or Web SQL Database. The biggest difference from traditional databases is that IndexedDB uses object storage instead of tables to store data . An IndexedDB database is a set of object stores under a common namespace, similar to a NoSQL-style implementation. Since it is a database, it is not the level of 5M and 10M. In theory, IndexedDB has no storage upper limit (generally not less than 250M).
1. Features of IndexedDB
- Key-value pair storage.
IndexedDB uses an object store to store data internally. All types of data can be stored directly, including JavaScript objects. In the object warehouse, data is stored in the form of "key-value pairs". Each data record has a corresponding primary key. The primary key is unique and cannot be repeated, otherwise an error will be thrown.
- asynchronous
IndexedDB is almost entirely asynchronous by design. To this end, most operations are performed in the form of requests, which are executed asynchronously, producing either a successful result or an error. The vast majority of IndexedDB operations require the addition of onerror and onsuccess event handlers to determine output. IndexedDB does not lock the browser when operating, and users can still perform other operations, which is in contrast to localStorage, which operates synchronously. Asynchronous design is to prevent the reading and writing of large amounts of data, which slows down the performance of web pages.
- Support transactions.
IndexedDB supports transactions, which means that in a series of operation steps, as long as one step fails, the entire transaction is cancelled, and the database is rolled back to the state before the transaction occurred, and there is no situation where only part of the data is rewritten.
- homology restriction
IndexedDB is subject to the same-origin restriction, and each database corresponds to the domain name that created it . Web pages can only access databases under their own domain names, but cannot access databases across domains.
- Large storage space
The storage space of IndexedDB is much larger than that of localStorage, generally not less than 250MB, and there is even no upper limit.
- Binary storage is supported.
IndexedDB can store not only strings but also binary data (ArrayBuffer objects and Blob objects).
2. IndexedDB usage process
Most of the operations in IndexedDB are not the mode of calling methods and returning results that we commonly use, but the mode of request-response.
Next, through a basic IndexedDB usage process, we aim to form a perceptual understanding of IndexedDB:
- Open/create an IndexedDB database (when the database does not exist, the open method will directly create a new database named admin)
let db
const request = window.indexedDB.open("admin", 1)
request.onerror = function(event) {
console.log('Not available IndexedDB')
}
request.onsuccess = function(event){
db = event.target.result
console.log("you opened IndexedDB")
}
Create an object store (the object store is mapped to the "table" unit in the database)
request.onupgradeneeded = function(event){
let objectStore
if (!db.objectStoreNames.contains('test')) {
objectStore = db.createObjectStore('test', { keyPath: 'id' })
}
}
Build a transaction to perform some database operations like adding or fetching data, etc.
const transaction = db.transaction(["test"],"readwrite")
const objectStore = transaction.objectStore("test")
objectStore.add({id: 1, name: 'rendc'})
Wait for the operation to complete by listening to the correct type of event.
transaction.oncomplete = function(event) {
console.log("Successful operation ")
}
transaction.onerror = function(event) {
console.log("here is one Error")
}
3. Differences between Web Storage, cookies and IndexedDB
With these storage means; it is possible to store considerable data on the client side by using JavaScript. Because these data are not encrypted, be careful not to use them to store sensitive information.
Summarize
It is the emergence and development of browser storage and caching technologies that have brought infinite opportunities for our front-end applications. In recent years, third-party libraries based on storage and caching technologies have emerged, and excellent Web application models such as PWA have also been derived. Summarize some key points of this article:
- A cookie's job is not to store it locally, but to "maintain state".
- Web Storage defines two objects for storing data: sessionStorage and localStorage. The former is used to strictly save the data during one session of the browser, because the data will be deleted when the browser is closed. The latter is used to persist data outside the session.
- IndexedDB is a structured data storage mechanism similar to SQL databases. The difference is that IndexedDB stores objects, not tables.