CORS for cross domain resource sharing

1. What is CORS?

CORS is a W3C standard, and its full name is "Cross-origin resource sharing". It allows browsers to send XMLHttpRequest requests to cross-origin (protocol + domain name + port) servers, thus overcoming the limitation that AJAX can only be used on the same origin.

CORS requires both browser and server support. Its communication process is completed automatically by the browser without user participation. For developers, there is no difference between CORS communication and same-origin AJAX communication, and the code is exactly the same. Once the browser discovers that the AJAX request is cross-origin, it will automatically add some additional header information, and sometimes there will be an additional request, but the user will not feel it. Therefore, the key to realizing CORS communication is the server. As long as the server implements the CORS interface, cross-origin communication is possible.

2. Why use CORS?

When we need to make a technical decision, we often need to give appropriate reasons. As far as CORS is concerned, the fundamental reason for using it is to complete cross-domain access to resources, that is, how to bypass the Same-origin Policy.

So what is Same-origin Policy? Simply put, a website accessed in one browser cannot access data in another website, unless the two websites have the same origin, that is, the same protocol, host address, and port. Once one of these three items of data is different, the resource will be considered to be obtained from a different origin and will not be allowed to access.

But this restriction is too restrictive: a large website often has a series of subdomains. Data exchange between these domains will be restricted by Same-origin Policy. In order to bypass this limitation, the industry has proposed a series of methods to solve this problem, such as: changing the document.domain property , cross-document messages , JSONP and CORS , etc. Each of these solutions has its own advantages, so we need to choose these solutions according to different needs.

2.1. Change the document.domain property

It can be said that the method of changing the document.domain property is the most direct and fast method, and it is also relatively common. By setting the document.domain property of scripts from different domains to the same value, these scripts can be made to interact with each other. For example, the webpage obtained from "http://blog.ambergarden.com" can change the domain recorded in its document.domain attribute by executing the following script:

 1 document.domain = 'aitouch.com';

Then next, the script can access the data in ambergarden.com. This approach also has its own disadvantages, that is, software developers cannot set the value of the document.domain property arbitrarily, at least on some browsers.

2.2. Cross-document messages

Cross-document messaging is accomplished by sending messages to the Window instance. When in use, software developers need to send a message to the Window instance by calling a Window's postMessage() function. At this time, the onmessage event inside the Window instance will be triggered, and then the message processing function of the event will be called. But when receiving a message, the message processing function first needs to judge the legitimacy of the message source, so as to prevent malicious users from illegally executing code by sending messages.

2.3、JSONP

JSONP returns data from another domain by embedding a <script> tag in the document. For example, add a <script> tag to the page as follows:

1 <script src="http://blog.ambergarden.com/someData?callback=some_func"/>

The <script> tag will send a GET request to http://blog.ambergarden.com/someData . After the data is returned to the client, the some_func() function will be called. Of course, this method has a significant disadvantage, that is, only GET operations are supported.

3. CORS operation process

CORS divides requests that lead to cross-domain access into two types: Simple Request (simple request), not-so-simple request (non-simple request)

3.1. If a request does not contain any custom request headers, and the HTTP verb it uses is one of GET, HEAD or POST, then it is a Simple Request. But when using POST as the verb of the request, the Content-Type of the request needs to be one of application/x-www-form-urlencoded, multipart/form-data or text/plain.

3.2. If a request contains any custom request headers, or the HTTP verb it uses is any verb other than GET, HEAD or POST, then it is a not-so-simple request, also called Preflighted Request (Preflighted Request) inspection). If the Content-Type of the POST request is not one of application/x-www-form-urlencoded, multipart/form-data or text/plain, it is also a Preflighted Request. When the browser sends out a CORS non-simple request, it will add an HTTP query request before the formal communication, which is called a "preflight" request (preflight). The browser first asks the server whether the domain name of the current web page is in the server's permission list, and which HTTP verbs and header information fields can be used. Only when a positive reply is received, the browser will issue a formal XMLHttpRequest request, otherwise an error will be reported.

3.3. Under normal circumstances, a cross-domain request will not contain the user credentials of the current page. Once a cross-origin request includes the user credentials of the current page, it belongs to Requests with Credential.

3.4. Now let's look at an example of a simple request for cross-domain access through CORS. Suppose ambergarden.com wants to return some data from a public data platform public-data.com, then in the page logic, it can send a data request to public-data.com through the following code:

1 function retrieveData() {
2     var request = new XMLHttpRequest();
3     request.open('GET', 'http://public-data.com/someData', true);
4     request.onreadystatechange = handler;
5     request.send();
6 }

After running this code, the browser sends the following request to the service:

1 GET /someData/ HTTP/1.1
2 Host: public-data.com
3 ......
4 Referer: http://ambergarden.com/somePage.html
5 Origin: http://ambergarden.com

And a service that supports the CORS protocol might give the following response:

1 HTTP/1.1 200 OK
2 Access-Control-Allow-Origin: http://ambergarden.com
3 Content-Type: application/xml
4 ......
5 
6 [Payload Here]

3.5. We have already seen how the browser handles Simple Request. Then let's take a look at how the Preflight Request is executed. Compared with Simple Request, the operation process of Preflight Request is slightly more complicated.

  Suppose now we want to write some data to the public data platform public-data.com, then we need to send a POST request:

1 function sendData() {
2     var request = new XMLHttpRequest(),
3         payload = ......;
4     request.open('POST', 'http://public-data.com/someData', true);
5     request.setRequestHeader('X-CUSTOM-HEADER', 'custom_header_value');
6     request.onreadystatechange = handler;
7     request.send(payload);
8 }

After executing this code, the browser's first request will look like this:

1 OPTIONS /someData/ HTTP/1.1
2 Host: public-data.com
3 ......
4 Origin: http://ambergarden.com
5 Access-Control-Request-Method: POST
6 Access-Control-Request-Headers: X-CUSTOM-HEADER

As you can see, the first thing we send is not a POST request, but an OPTION request. The request also marks the request type and the custom HTTP Header contained in the request through Access-Control-Request-Method and Access-Control-Request-Headers. In fact, it is equivalent to asking the server for permission to access resources: "Hello, I want to send data to you, can you see it?". Sending a request for detection before actually accessing the resource is also the reason why the request is called a Preflight Request.

  After the server sees the OPTIONS request, it will analyze the content in the request and return a response to inform the browser whether it is allowed to send data to it:

1 HTTP/1.1 200 OK
2 Access-Control-Allow-Origin: http://ambergarden.com
3 Access-Control-Allow-Methods: POST, GET, OPTIONS
4 Access-Control-Allow-Headers: X-CUSTOM_HEADER
5 Access-Control-Max-Age: 1728000
6 ......

After the browser analyzes the response and understands that it is allowed to send data to the server, it will send the real POST request to the server:

1 POST /someData/ HTTP/1.1
2 Host: public-data.com
3 X-CUSTOM-HEADER: custom_header_value
4 ......
5 
6 [Payload Here]

The server will receive and process the request:

1 HTTP/1.1 200 OK
2 Access-Control-Allow-Origin: http://ambergarden.com
3 Content-Type: application/xml
4 ......
5 
6 [Payload Here]

  The operation process of the last request Requests with Credential is similar to the first two requests. It's just that when sending the request, we need to include the user credentials in the request:

1 function retrieveData() {
2     var request = new XMLHttpRequest();
3     request.open('GET', 'http://public-data.com/someData', true);
4     request.withCredentials = true;
5     request.onreadystatechange = handler;
6     request.send();
7 }

In the server's response, it will have an additional Access-Control-Allow-Credentials response header:

1 HTTP/1.1 200 OK
2 Access-Control-Allow-Credentials: true
3 Access-Control-Allow-Origin: http://ambergarden.com
4 Content-Type: application/xml
5 ......

4. Explanation of configuration items

4.1 Access-Control-Allow-Origin

This field is required. Its value is either the specific value of the Origin field in the request, or a *, which means accepting requests from any domain name.

4.2 Access-Control-Allow-Methods

This field is required. Its value is a specific string or * separated by commas, indicating all cross-domain request methods supported by the server. Note that all supported methods are returned, not just the one requested by the browser. This is to avoid multiple "preflight" requests.

4.3 Access-Control-Expose-Headers

 This field is optional. When CORS requests, the getResponseHeader() method of the XMLHttpRequest object can only get 6 basic fields: Cache-Control, Content-Language, Content-Type, Expires, Last-Modified, Pragma. If you want to get other fields, you must specify them in Access-Control-Expose-Headers.

4.4 Access-Control-Allow-Credentials

This field is optional. Its value is a boolean indicating whether to allow sending cookies. By default, no cookies occur, ie: false. For requests with special requirements on the server, such as the request method is PUT or DELETE, or the type of the Content-Type field is application/json, this value can only be set to true. If the server does not want the browser to send cookies, just delete this field.

4.5 Access-Control-Max-Age

This field is optional and is used to specify the validity period of this preflight request, in seconds. During the validity period, another preflight request does not need to be issued.

Note : When CORS requests to send cookies, Access-Control-Allow-Origin can only be the same domain name as the requested web page. At the same time, cookies still follow the same-origin policy. Only cookies set with the server domain name will be uploaded, and cookies from other domain names will not be uploaded, and the document.cookie in the (cross-origin) original web page code cannot read the Cookies.

Guess you like

Origin blog.csdn.net/weixin_43845075/article/details/93854832