background

Front-end and back-end requests interact. If the requester (Client) and the responder (Server) are in different domain names, cross-domain requests will occur. Different domains mean that one or all of the HTTP protocols, domain names, and ports are different. CORS is a mechanism to resolve cross-domain requests for resources that are restricted by browsers for security reasons from within scripts.

First, what CORS

CORS stands for “cross-domain resource sharing”. It is a mechanism that allows Web applications on Origin to access different source server resources by adding additional HTTP headers. CORS can be used in XMLHttpRequest and Fetch to initiate cross-domain requests.

Ii. Working principle of CORS

For front-end development, it does not need extra work to use CORS to initiate cross-domain requests. When the request occurs, the browser will automatically set the corresponding HTTP header information (as described below), and the server needs to do the corresponding header Settings to control cross-domain permissions.

1. Initiate a request

Cross-domain requests initiated by CORS can be classified into simple requests and non-simple requests. Simple requests do not trigger OPTIONS pre-check requests, but cross-domain requests can be directly initiated. Non-simple requests trigger OPTIONS pre-check requests, and some query information is sent to the server, such as: Whether to allow this cross-domain request, tell what request method to use, and whether to support carrying custom fields in HTTP headers.

1.1 Simple Request

A simple request can be made directly to the server. As long as the server agrees to the cross-domain request, the browser can obtain the resources returned by the server. A simple request is made as long as the following conditions are met at the same time.

A. Use one of GET, POST, and HEAD request methods.

B. Do not set header information set fields other than Accept, accept-language, content-language, and content-Type. You cannot set values other than text/plain, multipart/form-data, application/ X-www-form-urlencode for content-type values.

C. None of the XMLHttpRequestupload objects in the request have any listeners set.

D. No ReadableStream object is used in the request.

A simple example

var request = new XMLHttpRequest()
var url = 'http://bar.other/resources/public-data/'

function callOtherDomain() {
  if(invocation) {    
    invocation.open('GET', url, true);
    invocation.onreadystatechange = handler;
    invocation.send(); 
  }
}
//发起请求
callOtherDomain()
Copy the code

Cross-domain permissions are processed between the Client and Server through HTTP header fields when a request is sent.

HTTP request header information
2. Host: bar.other 3. User-agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; 4. The rv: 1.9.1 b3pre) Gecko / 20081130 Minefield / 3.1 b3pre 5. Accept: text/HTML, application/XHTML + XML, application/XML. Q = 0.9 * / *; Q = 0.8 6. Accept - Language: en - us, en. 8. Accept-charset: ISO-8859-1, UTF-8; Q = 0.7 *; Q =0.7 9.connection: keep-alive 10.referer: http://foo.example/examples/access-control/simpleXSInvocation.html 11. Origin: http://foo.exampleCopy the code
Server response header information
Date: Mon, 01 Dec 2008 00:23:53 GMT 3. Server: Apache/2.0.61 4. Access-control-allow-origin: * 5. Keep-Alive: timeout=2, max=100 6. Connection: Keep-Alive 7. Transfer-Encoding: chunked 8. Content-Type: application/xmlCopy the code

The Client uses the Origin field to tell the Server that I am a request from http://foo.example. Am I allowed to access your resources? The Server responds with access-Control-allow-origin :* in the response header to indicate that I Allow all outer domains to Access my resources.

If the access-Control-allow-origin value is set to http://foo.example, only sources from http://foo.example are allowed to Access resources on the Server. Background development typically adds a whitelist of request sources here to control which request sources are allowed access to service resources.

If Origin is not an access-Control-allow-Origin source, the browser intercepts the request response content and cannot obtain server resources.

1.2 Non-simple Requests

Any request that does not satisfy a simple request is a non-simple request. A non-simple request triggers an Options pre-check request before a formal resource access request is initiated. The options request does not affect resources on the server. A precheck request is triggered if one of the following conditions is met:

A. PUT, DELETE, CONNECT, OPTIONS, TRACE, PATCH.

B. Set Accept accept-language, content-language, content-type (note additional restrictions), DPR, Downlink, save-data, viewport-width, Width field.

C. Content-type values do not belong to one of Application/X-www-form-urlencoded, multipart/form-data, text/plain.

D. The XMLHttpRequestUpload object in the request registers any number of event listeners.

E. The request uses a ReadableStream object.

Again, to borrow an example from MSDN

var invocation = new XMLHttpRequest();
var url = 'http://bar.other/resources/post-here/';
var body = '
      
      
       
        Arun
       
      ';
    
function callOtherDomain() {if(invocation)
    {
      invocation.open('POST', url, true);
      invocation.setRequestHeader('X-PINGOTHER'.'pingpong');
      invocation.setRequestHeader('Content-Type'.'application/xml'); invocation.onreadystatechange = handler; invocation.send(body); }} // call callOtherDomain()Copy the code

As you can see in the code, we have artificially defined the X-Pingother request header field (satisfying the non-simple request B condition), and the Content-Type is set to Application/XML (satisfying the non-simple request C condition), so the request will first trigger an Options request.

Here is some information about the options request header:

1.OPTIONS /resources/post-here/ HTTP/1.1 2.Host: bar.other 3. U; Intel Mac OS X 10.5; en-US; The rv: 1.9.1 b3pre) Gecko / 20081130 Minefield / 3.1 b3pre 4. Accept: text/HTML, application/XHTML + XML, application/XML. Q = 0.9 * / *; Q = 0.8 5. Accept - Language: en - us, en. 7. Accept-charset: ISO-8859-1, UTF-8; Q = 0.7 *; Q =0.7 8.Connection: keep-alive 9.Origin: http://foo.example 10. access-Control-request-method: POST 11.Access-Control-Request-Headers: X-PINGOTHER, Content-TypeCopy the code

The options request tells the Server that I am a request from http://foo.example. In a formal request, I will carry custom fields x-pingother and conten-type in the request header and I will initiate the request via POST. Do you agree? Here are the header information fields used to ask the Server:

Origin: http://foo.example
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-PINGOTHER, Content-Type
Copy the code

How does the Server respond to the options request

Date: Mon, 01 Dec 2008 01:15:39 GMT 2.Server: Apache/2.0.61 (Unix) 3. Access-control-allow-origin: http://foo.example 4.Access-Control-Allow-Methods: POST, GET, OPTIONS 5.Access-Control-Allow-Headers: X-PINGOTHER, Content-Type 6.Access-Control-Max-Age: 86400 7.Vary: Accept-Encoding, Origin 8.Content-Encoding: gzip 9.Content-Length: 0 10.Keep-Alive: timeout=2, max=100 11.Connection: Keep-Alive 12.Content-Type: text/plainCopy the code

The access-Control-allow-origin field indicates that the server allows http://foo.example to Access the resource. The access-Control-allow-headers field indicates that the server allows x-Pingother and Content-Type fields to be carried in the request header. Access-control-allow-methods Indicates that formal requests are allowed to use the POST method. The options request ends. If the Server agrees to access, a formal request is made, otherwise the request ends.

There is an access-Control-max-age: 86400 message in line 6, which means that no options pre-check request is issued for the same request for the next 86400 seconds. Access-control-max-age Is set by the background and cannot exceed the maximum validity period supported by the browser. Otherwise, it does not take effect.

2. Requests with credentials

Fetch and CORS can send identity credentials based on HTTP cookies and HTTP authentication information. In general, browsers do not send identity credentials for cross-domain XMLHttpRequest or Fetch requests.

To send credential information, set XMLHttpRequest withCredentials=true, and set the access-Control-allow-credentials header field on the Server: Otherwise, the browser intercepts the response and does not return it to the request sender.

Note that if access-Control-allow-origin: * is set to the Server, the request will fail if cookies are also sent.

3. Fields in the cross-domain request header and response header

3.1 Request Header Fields

The Origin field indicates the source of the precheck request or the actual request, and the value of the Origin parameter is the source URI. It does not contain any path information, just the server name, and the Origin field is sent whether it is a cross-domain request or not.

Origin: <origin>
Copy the code

The access-Control-request-method field is used to precheck the Request. It tells the server the HTTP method used for the actual request.

Access-Control-Request-Method: <method>
Copy the code

The access-Control-request-HEADERS field is used to pre-check the Request. This tells the server the header field carried by the actual request.

Access-Control-Request-Headers: <field-name>[, <field-name>]*
Copy the code

3.2 Response header Fields

Access-control-allow-origin field. The value of the Origin parameter specifies the outer domain URI that is allowed to Access the resource. For requests that do not require credentials, the server can specify the value of this field as a wildcard, indicating that requests from all domains are allowed.

Access-Control-Allow-Origin: <origin> | *
Copy the code

The access-Control-expose-headers field sets the whitelist of header fields available to the browser. In cross-domain access, the getResponseHeader() method of the XMLHttpRequest object takes only the most basic response headers, Cache-control, Content-language, Content-Type, Expires, last-Modified, Pragma. To access other headers, the server needs to set this response header. That’s where access-Control-expose-headers comes in.

Access-Control-Expose-Headers: X-My-Custom-Header, X-Another-Custom-Header
Copy the code

The access-Control-max-age field sets how long the predetection request can be cached, in seconds.

Access-Control-Max-Age: <delta-seconds>
Copy the code

The access-Control-allow-credentials field specifies whether the browser is allowed to read the response when the browser’s Credentials are set to true

Access-Control-Allow-Credentials: true
Copy the code

The access-Control-allow-methods field is used to precheck the response to the request. This specifies the HTTP methods allowed for the actual request.

Access-Control-Allow-Methods: <method>[, <method>]*
Copy the code

The access-Control-allow-headers header field is used to pre-check the response to the request. This specifies the header field that is allowed in the actual request.

Access-Control-Allow-Headers: <field-name>[, <field-name>]*
Copy the code

4. The compatibility

Currently, Internet Explorer 9 and the following browsers do not support CORS, but other browsers do support CORS. For Internet Explorer 9 and below can be implemented through XDomainRequest.

The above is my summary and record of CORS knowledge. Since I frequently encountered cross-domain problems in my previous work, I decided to record them after thinking over and over. In order to ensure the correctness of information, I refer to official documents with great reference, hoping to help partners in need in dealing with cross-domain problems.

Disclaimer: The contents of this article refer to MDN official documents, including the case code used above is also borrowed from MDN, if there is infringement, please contact me to delete the relevant content.