Take a good look at cookies (strongly recommended) and learn about cookies

Source: Internet
Author: User
Tags string back aliyun

Take a good look at cookies (strongly recommended) and learn about cookies

Cookie Creation

Because HTTP is stateless, services on the server must be stateful. The initial purpose of Cookie creation is to store the status information on the web for the convenience of use by the server. For example, determine whether the user visits the website for the first time. Currently, the latest specification is RFC 6265, which is implemented by the collaboration of browser servers.

Cookie processing is divided:

The server sends a cookie like a client

The browser saves the cookie

The browser sends the cookie to the server every time the http request is sent.

Server-side sending and parsing

Send cookie

The Cookie sent by the server-side image client is implemented through the HTTP Response Message. in Set-Cookie, Set the cookie to be sent like the client. The cookie format is as follows:

Set-Cookie: "name = value; domain = .domain.com; path =/; expires = Sat, 11 Jun 2016 11:29:42 GMT; HttpOnly; secure"
Among them, name = value is a required option, and others are optional. Cookie mainly consists of the following:

Name: A unique cookie name. Generally, the cookie name is case-insensitive.

Value: the string value stored in the cookie. It is best to perform url encoding for the cookie name and value.

Domain: the domain in which the cookie is valid. All requests sent to this domain contain this cookie. This value can contain subdomains (for example:

Yq.aliyun.com) or not (for example, .aliyun.com ).

Path: indicates the path affected by the cookie. the browser will send the cookie based on this configuration, such as the matching path in the specified domain.

Expires: The expiration time, indicating when the cookie should be deleted (that is, when the cookie should be stopped from being sent to the server ). If this timestamp is not set, the browser will delete all cookies when the page is closed. However, you can set the deletion time on your own. This value is in GMT format. If the client and server time are inconsistent, there will be a deviation when using expires.

Max-age: works the same as expires to tell the browser how long the cookie expires (in seconds), rather than a fixed time point. In normal cases, the priority of max-age is higher than that of expires.

HttpOnly: indicates that the browser cannot change this value through the script document. cookie, which is also invisible to document. cookie. However, the cookie is still carried in the http request. Note that this value is not available in the script, but still exists in the browser installation directory as a file. This setting is usually set on the server side.

Secure: security flag. After the security flag is specified, it can be sent to the server only when the SSL link is used. If it is an http link, this information will not be transmitted. Even if the secure attribute is set, it does not mean that others cannot see the cookie information stored locally on your machine. Therefore, do not set important information on the server simply by placing the cookie.

Cookie example:

var http = require('http');
var fs = require('fs');
http.createServer(function(req, res) {
  res.setHeader('status', '200 OK');
  res.setHeader('Set-Cookie', 'isVisit=true;domain=.yourdomain.com;path=/;max-age=1000');
  res.write('Hello World');
  res.end();
}).listen(8888);
console.log('running localhost:8888')


Directly setting Set-Cookie is too primitive. We can encapsulate the cookie setting process as follows:

var serilize = function (name, val, options) {
   if (! name) {
     throw new Error ("coolie must have name");
   }
   var enc = encodeURIComponent;
   var parts = [];
  
   val = (val! == null && val! == undefined)? val.toString (): "";
   options = options || {};
   parts.push (enc (name) + "=" + enc (val));
   // domain must contain two dots
   if (options.domain) {
     parts.push ("domain =" + options.domain);
   }
   if (options.path) {
     parts.push ("path =" + options.path);
   }
   // If expires and max-age are not set, the browser will clear cookies when the page is closed
   if (options.expires) {
     parts.push ("expires =" + options.expires.toGMTString ());
   }
   if (options.maxAge && typeof options.maxAge === "number") {
     parts.push ("max-age =" + options.maxAge);
   }
   if (options.httpOnly) {
     parts.push ("HTTPOnly");
   }
   if (options.secure) {
     parts.push ("secure");
   }
  
   return parts.join (";");
}

Note that if you set a previous time for the cookie, the browser will immediately delete the cookie. In addition, the domain item must have two points, so it cannot be set as localhost:

something that wasn't made clear to me here and totally confused me for a while was that domain names must contain at least two dots (.),hence 'localhost' is invalid and the browser will refuse to set the cookie!

Server-side cookie resolution

Cookie can set different domains and paths. Therefore, for the same name value, it can be repeated in different paths of different domains, the browser will sort the order in which the url or page address of the current request is best matched


Therefore, when the front-end sends a cookie to the server with multiple duplicate name values, we only need the one that matches the most, that is, the first one. The server-side Parsing Code is as follows:

var parse = function (cstr) {
   if (! cstr) {
     return null;
   }
  
   var dec = decodeURIComponent;
   var cookies = ();
   var parts = cstr.split (/ \ s *; \ s * / g);
   parts.forEach (function (p) {
     var pos = p.indexOf ('=');
     // name and value must be encoded before they are stored in the cookie
     var name = pos> -1? dec (p.substr (0, pos)): p;
     var val = pos> -1? dec (p.substr (pos + 1)): null;
     // Just get the one that matches
     if (! cookies.hasOwnProperty (name)) {
       cookies [name] = val;
     } / * else if (! cookies [name] instanceof Array) {
       cookies [name] = [cookies [name]]. push (val);
     } else {
       cookies [name] .push (val);
     } * /
   });
  
   return cookies;
}

Client Access

The browser manages the cookies passed in the background and allows developers to use document. cookie in JavaScript to access cookies. However, this interface is very poor. It will show different behaviors because it is used in different ways.

When used to obtain the property value, document. cookie returns all available strings (based on the cookie domain, path, expiration time, and security settings) on the current page. The format of the string is as follows:

"name1=value1;name2=value2;name3=value3";

When used to set the value, the document. cookie attribute can be set as a new cookie string. This string will be interpreted and added to the existing cookie set. For example:

document.cookie = "_fa=aaaffffasdsf;domain=.dojotoolkit.org;path=/"

Setting document. cookie does not overwrite the cookie unless the configured name value domain path is the same as an existing cookie.

Because it is inconvenient to read and write cookies, We can encapsulate some functions to process cookies, mainly for adding, modifying, and deleting cookies.

var cookieUtils = {
    get: function (name) {
     var cookieName = encodeURIComponent (name) "=";
     // Only get the best matching name, value
     var cookieStart = document.cookie.indexOf (cookieName);
     var cookieValue = null;
     
     if (cookieStart> -1) {
      // from cookieStart
      var cookieEnd = document.cookie.indexOf (';', cookieStart);
      // start from =
      if (cookieEnd> -1) {
       cookieValue = decodeURIComponent (document.cookie.substring (cookieStart cookieName.length, cookieEnd));
      } else {
       cookieValue = decodeURIComponent (document.cookie.substring (cookieStart cookieName.length, document.cookie.length));
      }
     }
     
     return cookieValue;
    },
    
    set: function (name, val, options) {
      if (! name) {
        throw new Error ("coolie must have name");
      }
      var enc = encodeURIComponent;
      var parts = [];
      
      val = (val! == null && val! == undefined)? val.toString (): "";
      options = options || {};
      parts.push (enc (name) "=" enc (val));
      // domain must contain two dots
      if (options.domain) {
        parts.push ("domain =" options.domain);
      }
      if (options.path) {
        parts.push ("path =" options.path);
      }
      // If expires and max-age are not set, the browser will clear cookies when the page is closed
      if (options.expires) {
        parts.push ("expires =" options.expires.toGMTString ());
      }
      if (options.maxAge && typeof options.maxAge === "number") {
        parts.push ("max-age =" options.maxAge);
      }
      if (options.httpOnly) {
        parts.push ("HTTPOnly");
      }
      if (options.secure) {
        parts.push ("secure");
      }
      
      document.cookie = parts.join (";");
    },
    delete: function (name, options) {
     options.expires = new Date (0); // Set to a past date
     this.set (name, null, options);
    }
   }

Cache advantages

Generally, Web Cache refers to an http device that can automatically save copies of common http requests. Browser plays an important role for front-end developers. In addition, a variety of proxy servers can also be used for caching. When a Web request arrives at the cache, the cache extracts the copy content from the local copy without going through the server. This brings the following advantages:

Cache reduces redundant data transmission and reduces traffic

The cache relieves the bandwidth bottleneck. Page loading can be faster without more bandwidth

The cache reduces instant congestion and original server requirements.

The cache reduces the latency because loading pages from a distant location is slower.

Cache type

The cache can be private to a single user or shared by multiple users. Private cache is called Private cache, and shared cache is called public cache.

Private Cache

Private cache is only for private users, so it does not need much space and is cheap. There is a built-in private cache in the Web browser-most browsers will cache common resources in the disk and memory of your PC. For example, the Cache storage location of Chrome is in the Cache folder and Media Cache folder in C: \ Users \ Your_Account \ AppData \ Local \ Google \ Chrome \ User Data \ Default.

Public Cache

Public cache is a special shared proxy server. It is called a cache proxy server or a proxy cache (a purpose of reverse proxy ). The public cache will accept access from multiple users, so it can better reduce redundant traffic.
Each client repeatedly accesses a resource to the server (which is not in the private cache at this time). In this way, the client accesses the server multiple times, increasing the pressure on the server. When using the shared public cache, the cache only needs to be retrieved from the server once, and no longer needs to go through the server, which can significantly reduce the pressure on the server.


In fact, hierarchical public cache is usually used in practical applications. The basic idea is to use small and low-cost caches near the client, but at a higher level, more and more powerful caches are gradually used to load resources shared by multiple users.

Cache processing process


For front-end developers, the process is simplified:


The following figure shows the request results for different resources on a website. Some resources are directly read from the cache, and some resources are reverified with the server, some resources are retrieved from the server again.


Note that all the questions we discuss about cache resources are only for GET requests. Action-based operations such as POST, DELETE, and PUT are usually not cached.

Freshness limit

HTTP caches copies of server resources for a period of time, which is called the freshness limit. In this case, requests for the same resource within a period of time will no longer pass through the server. Cache-Control and Expires in HTTP can be used to set the freshness limit. The former is the newly added response header in HTTP1.1, and the latter is the response header in HTTP1.0. The two do the same thing, but because Cache-Control uses relative time, Expires may have time difference between the client and the server, therefore, we prefer Cache-Control.

Cache-Control

Next let's take a look at the attribute values that can be set in Cache-Control:

Max-age (unit: s) specifies the maximum cache validity period, which defines the duration. After the browser sends a request to the server, the browser will not send the request to the server during the max-age period.

<html>
 <head>
  <meta http-equiv = "Content-Type" content = "text / html; charset = utf-8">
  <meta name = "viewport" content = "width = device-width, initial-scale = 1.0, maximum-scale = 1.0, user-scalable = no" />
  <meta http-equiv = "X-UA-Compatible" content = "IE = EDGE" />
  <title> Web Cache </ title>
  <link rel = "shortcut icon" href = "./ shortcut.png">
  <script>
  </ script>
 </ head>
 <body class = "claro">
 <img src = "./ cache.png">
 </ body>
</ html>
var http = require ('http');
var fs = require ('fs');
http.createServer (function (req, res) {
  if (req.url === '/' || req.url === '' || req.url === '/index.html') {
    fs.readFile ('./ index.html', function (err, file) {
      console.log (req.url)
      // Set the cache for the main document, no effect
      res.setHeader ('Cache-Control', "no-cache, max-age =" + 5);
      res.setHeader ('Content-Type', 'text / html');
      res.writeHead ('200', "OK");
      res.end (file);
    });
  }
  if (req.url === '/cache.png') {
    fs.readFile ('./ cache.png', function (err, file) {
      res.setHeader ('Cache-Control', "max-age =" + 5); // cache for five seconds
      res.setHeader ('Content-Type', 'images / png');
      res.writeHead ('200', "Not Modified");
      res.end (file);
    });
  }
  
}). listen (8888)
When the page is accessed for the second time within 5 seconds, the browser will fetch resources directly from the cache
public specifies that the response can be cached in the proxy cache, so it can be shared by multiple users. If private is not explicitly specified, it defaults to public.
Private responses can only be cached in the private cache, not on the proxy cache. Resources that are sensitive to some user information usually need to be set to private.
no-cache means that you must confirm with the server whether the resource has been changed (relying on If-None-Match and Etag) before deciding whether to use the local cache.
If the above processing of cache.png is changed to the following, each time you visit the page, the browser needs to go to the server to verify that the resources have not been changed.

fs.readFile ('./ cache.png', function (err, file) {
    console.log (req.headers);
    console.log (req.url)
    if (! req.headers ['if-none-match']) {
      res.setHeader ('Cache-Control', "no-cache, max-age =" + 5);
      res.setHeader ('Content-Type', 'images / png');
      res.setHeader ('Etag', "ffff");
      res.writeHead ('200', "Not Modified");
      res.end (file);
    } else {
      if (req.headers ['if-none-match'] === 'ffff') {
        res.writeHead ('304', "Not Modified");
        res.end ();
      } else {
        res.setHeader ('Cache-Control', "max-age =" + 5);
        res.setHeader ('Content-Type', 'images / png');
        res.setHeader ('Etag', "ffff");
        res.writeHead ('200', "Not Modified");
        res.end (file);
      }
    }
  });

no-store absolutely prohibits caching any resources, which means that every time a user requests a resource, a request is sent to the server, and the complete resource is downloaded each time. Usually used for confidential resources.

Regarding the use of Cache-Control, see the following picture (from large amount)
Client Freshness Limit

Cache-Control can be set not only in the response header, but also in the request header. The browser can decide whether to read resources from the cache by setting Cache-Control in the request header. This is also why sometimes when you click the browser refresh button and enter in the address bar, you see completely different results in the NetWork module
Expires
Expires is deprecated, it specifies a specific expiration date instead of seconds. Because many servers and clients have inconsistent clocks, it is better to use Cache-Control.

Server reauthentication

The expired resource cached in the browser or proxy cache does not mean that it is actually different from the resource on the original server, it just means that it is time to check. This situation is called server reauthentication.

If the resource changes, you need to get the new resource and replace the old resource in the cache.
If the resource has not changed, the cache only needs to obtain a new response header and a new expiration time, and update the resource expiration time in the cache.
The recommended authentication method used in HTTP 1.1 is If-None-Match / Etag. In HTTP 1.0, If-Modified-Since / Last-Modified is used.
Etag and If-None-Match
Generate a hash string according to the entity content, which identifies the status of the resource, which is generated by the server. The browser will send this string back to the server to verify whether the resource has been modified. If it has not been modified, the process is as follows (picture from the Web cache):

In the demo above, we saw how to verify Etag on the server side:

Because Etag has a server structure, it must be unique in a cluster environment.

If-Modified-Since and Last-Modified

These two are the request / response headers used to verify whether the resource has expired in HTTP 1.0. These two headers are dates. The verification process is similar to Etag and will not be described in detail here. When using these two headers to verify that a resource is updated, the following issues exist:

Some document resources are rewritten periodically, but the actual content has not changed. At this time, the file's metadata will show that the latest modification date of the file is different from If-Modified-Since, resulting in unnecessary response.

Some document resources have been modified, but the content of the changes is not important and does not require all caches to be updated (such as code comments)

Regarding the cache update, please take a look at Zhang Yunlong's answer here, this article will not expand in detail.

The demo code in this article is as follows:

<! DOCTYPE HTML>
<html>
 <head>
  <meta http-equiv = "Content-Type" content = "text / html; charset = utf-8">
  <meta name = "viewport" content = "width = device-width, initial-scale = 1.0, maximum-scale = 1.0, user-scalable = no" />
  <meta http-equiv = "X-UA-Compatible" content = "IE = EDGE" />
  <title> Web Cache </ title>
  <link rel = "shortcut icon" href = "./ shortcut.png">
  <script>
  </ script>
 </ head>
 <body class = "claro">
 <img src = "./ cache.png">
 </ body>
</ html>
var http = require ('http');
var fs = require ('fs');
http.createServer (function (req, res) {
  if (req.url === '/' || req.url === '' || req.url === '/index.html') {
    fs.readFile ('./ index.html', function (err, file) {
      console.log (req.url)
      // Set the cache for the main document, no effect
      res.setHeader ('Cache-Control', "no-cache, max-age =" + 5);
      res.setHeader ('Content-Type', 'text / html');
      res.writeHead ('200', "OK");
      res.end (file);
    });
  }
  if (req.url === '/shortcut.png') {
    fs.readFile ('./ shortcut.png', function (err, file) {
      console.log (req.url)
      res.setHeader ('Content-Type', 'images / png');
      res.writeHead ('200', "OK");
      res.end (file);
    })
  }
  if (req.url === '/cache.png') {
    fs.readFile ('./ cache.png', function (err, file) {
      console.log (req.headers);
      console.log (req.url)
      if (! req.headers ['if-none-match']) {
        res.setHeader ('Cache-Control', "max-age =" + 5);
        res.setHeader ('Content-Type', 'images / png');
        res.setHeader ('Etag', "ffff");
        res.writeHead ('200', "Not Modified");
        res.end (file);
      } else {
        if (req.headers ['if-none-match'] === 'ffff') {
          res.writeHead ('304', "Not Modified");
          res.end ();
        } else {
          res.setHeader ('Cache-Control', "max-age =" + 5);
          res.setHeader ('Content-Type ',' images / png ');
           res.setHeader ('Etag', "ffff");
           res.writeHead ('200', "Not Modified");
           res.end (file);
         }
       }
     });
   }
}). listen (8888)
Well, this article's introduction to cookies is over, I hope everyone will like it.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.