CORS is a W3C standard, the full name is "Cross-origin resource sharing". It allows browsers to issue
XMLHttpRequest requests to cross-domain servers, thus overcoming the limitation that AJAX can only be used from the same source.
CORS needs to be supported by both the browser and the server. Currently, all browsers support this feature.
The entire CORS communication process is done automatically by the browser and does not require user involvement. For developers, CORS communication is no different from ordinary AJAX communication, and the code is exactly the same. Once the browser finds that the AJAX request is cross-domain, it will automatically add some additional header information, and sometimes an additional request will be made, but the user will not perceive it. Therefore, the key to implementing CORS communication is the server. As long as the server implements the CORS interface, it can communicate across domains.
CORS requests are divided into two categories: simple requests and not-so-simple requests.
As long as the following two conditions are met at the same time, it is a simple request.
(1) The request method is one of the following three methods.
-HEAD -GET -POST
(2) The HTTP header information does not exceed the following fields.
-Accept -Accept-Language -Content-Language -Last-Event-ID -Content-Type: Limited to three values
Anything that does not meet the above two conditions at the same time is a non-simple request. In a word, a simple request is a combination of a simple HTTP method and simple HTTP header information.
The reason for this division is that forms have historically been able to make requests across domains. A simple request is a form request. The browser follows the traditional processing method and does not complicate the behavior, otherwise the developer may switch to using the form to circumvent the restrictions of CORS. For non-simple requests, the browser will adopt a new processing method.
For simple requests, the browser directly issues CORS requests. Specifically, in the header information, add an
The following is an example. The browser finds that this cross-domain AJAX request is a simple request, and automatically adds an Origin field to the header information.
GET /cors HTTP/1.1 Origin: http://api.bob.com Host: api.alice.com Accept-Language: en-US Connection: keep-alive User-Agent: Mozilla/5.0...
In the above header information, the
Origin field is used to indicate which domain (protocol + domain name + port) this request comes from. The server decides whether to approve this request based on this value.
If the source specified by
Origin is not within the permitted scope, the server will return a normal HTTP response. The browser found that the header of this response did not include the
Access-Control-Allow-Origin field (see below for details), and knew that there was an error, so an error was thrown, which was captured by the
onerror callback function of
XMLHttpRequest. Note that this error cannot be identified by the status code, because the status code of the HTTP response may be 200.
If the domain name specified by
Origin is within the permitted range, the response returned by the server will contain several more header fields.
Access-Control-Allow-Origin: http://api.bob.com Access-Control-Allow-Credentials: true Access-Control-Expose-Headers: FooBar Content-Type: text/html; charset=utf-8
In the header information above, there are three fields related to the CORS request, all of which start with
This field is required. Its value is either the value of the
Origin field in the request, or a
*, which means that the request for any domain name is accepted.
This field is optional. Its value is a Boolean value, which indicates whether to allow the sending of cookies. By default, cookies are not included in CORS requests. Set to
true, which means that the server clearly allows the browser to include the cookie in the request and send it to the server together. This value can only be set to
true. If the server does not want the browser to send cookies, just not send this field.
This field is optional. In CORS request, the
getResponseHeader() method of the
XMLHttpRequest object can only get the basic fields returned by the six servers:
Pragma. If you want to get other fields, you must specify them in
Access-Control-Expose-Headers. The above example specifies that
getResponseHeader('FooBar') can return the value of the
As mentioned above, the CORS request does not contain Cookie information (and HTTP authentication information, etc.) by default. This is to reduce the risk of CSRF attacks. However, in some cases, the server may need to obtain cookies. In this case, the server needs to explicitly specify the
Access-Control-Allow-Credentials field to tell the browser that cookies can be sent.
At the same time, the developer must open the
withCredentials property in the AJAX request.
var xhr = new XMLHttpRequest(); xhr.withCredentials = true;
Otherwise, even if the server requests to send cookies, the browser will not send them. Or, the server requires cookies to be set, and the browser will not process it either.
However, some browsers set the
withCredentials property to
true by default. This leads to the fact that if the
withCredentials setting is omitted, these browsers may still send cookies together. At this time, you can explicitly turn off
xhr.withCredentials = false;
It should be noted that if the server requires the browser to send cookies,
Access-Control-Allow-Origin cannot be set as an asterisk, and a clear domain name that is consistent with the requested webpage must be specified. At the same time, cookies still follow the same-origin policy, only cookies set with the server domain name will be uploaded, cookies of other domain names will not be uploaded, and (cross-domain) the
document.cookie in the original webpage code cannot read the server domain name. Cookies under.
Non-simple requests are those that make special requests to the server. For example, the request method is
DELETE, or the type of the
Content-Type field is
For CORS requests that are not simple requests, an HTTP query request will be added before the formal communication, called a "preflight" request (preflight). The browser first asks the server whether the domain name of the current webpage is in the server's permission list, and which HTTP methods and header fields can be used. Only after getting a positive answer, the browser will send a formal
XMLHttpRequest request, otherwise it will report an error. This is to prevent these new requests from putting pressure on traditional servers without CORS support, and to give the server an opportunity to reject them in advance. This prevents the server from receiving a large number of
PUT requests. These traditional forms do not Requests that may be made across domains.
var url = "http://api.alice.com/cors"; var xhr = new XMLHttpRequest(); xhr.open("PUT", url, true); xhr.setRequestHeader("X-Custom-Header", "value"); xhr.send();
In the above code, the HTTP request method is
PUT, and a custom header information
X-Custom-Header is sent.
The browser finds that this is a non-simple request, and automatically sends a "pre-check" request, asking the server to confirm that the request can be made. The following is the HTTP header information of this "preflight" request.
OPTIONS /cors HTTP/1.1 Origin: http://api.bob.com Access-Control-Request-Method: PUT Access-Control-Request-Headers: X-Custom-Header Host: api.alice.com Accept-Language: en-US Connection: keep-alive User-Agent: Mozilla/5.0...
The request method used for the "pre-check" request is
OPTIONS, which means that this request is for inquiry. In the header information, the key field is
Origin, which indicates which source the request comes from.
In addition to the
Origin field, the header information of the "preflight" request includes two special fields.
This field is required and used to list which HTTP methods will be used in the browser's CORS request. The above example is
This field is a comma-separated string that specifies the additional header fields that the browser will send in CORS requests. The example above is
Response to preflight request
After the server receives the "preflight" request, it checks the
Access-Control-Request-Headers fields, confirms that cross-origin requests are allowed, and can respond.
HTTP/1.1 200 OK Date: Mon, 01 Dec 2008 01:15:39 GMT Server: Apache/2.0.61 (Unix) Access-Control-Allow-Origin: http://api.bob.com Access-Control-Allow-Methods: GET, POST, PUT Access-Control-Allow-Headers: X-Custom-Header Content-Type: text/html; charset=utf-8 Content-Encoding: gzip Content-Length: 0 Keep-Alive: timeout=2, max=100 Connection: Keep-Alive Content-Type: text/plain
In the above HTTP response, the key is the
Access-Control-Allow-Origin field, which means that
http://api.bob.com can request data. This field can also be set as an asterisk, which means that any cross-origin request is agreed.
If the server denies the "preflight" request, it will return a normal HTTP response, but without any CORS-related header fields, or it clearly indicates that the request does not meet the conditions.
OPTIONS http://api.bob.com HTTP/1.1 Status: 200 Access-Control-Allow-Origin: https://notyourdomain.com Access-Control-Allow-Method: POST
In the server response above, the
Access-Control-Allow-Origin field clearly does not include the requesting
At this time, the browser will determine that the server does not agree with the preflight request, so an error is triggered, which is captured by the
onerror callback function of the
XMLHttpRequest object. The console will print out the following error message.
XMLHttpRequest cannot load http://api.alice.com. Origin http://api.bob.com is not allowed by Access-Control-Allow-Origin.
Other CORS-related fields responded by the server are as follows.
Access-Control-Allow-Methods: GET, POST, PUT Access-Control-Allow-Headers: X-Custom-Header Access-Control-Allow-Credentials: true Access-Control-Max-Age: 1728000
This field is required, and its value is a comma-separated string indicating all cross-domain request methods supported by the server. Note that all supported methods are returned, not just the method requested by the browser. This is to avoid multiple "preflight" requests.
If the browser request includes the
Access-Control-Request-Headers field, the
Access-Control-Allow-Headers field is required. It is also a comma-separated string indicating all header fields supported by the server, not limited to the fields requested by the browser in the "preflight".
This field has the same meaning as in a simple request.
This field is optional and is used to specify the validity period of this pre-check request, in seconds. In the above results, the validity period is 20 days (1728000 seconds), which means that the response is allowed to be cached for 1728000 seconds (20 days). During this period, there is no need to issue another pre-check request.
Normal browser request and response
Once the server passes the "pre-check" request, every subsequent normal CORS request from the browser will be the same as a simple request, with an
Origin header field. The server's response will also have an
Access-Control-Allow-Origin header field.
The following is the normal CORS request of the browser after the "preflight" request.
PUT /cors HTTP/1.1 Origin: http://api.bob.com Host: api.alice.com X-Custom-Header: value Accept-Language: en-US Connection: keep-alive User-Agent: Mozilla/5.0...
Origin field of the above header information is automatically added by the browser.
The following is the normal response of the server.
Access-Control-Allow-Origin: http://api.bob.com Content-Type: text/html; charset=utf-8
In the above header information, the
Access-Control-Allow-Origin field must be included in every response.
Comparison with JSONP
CORS has the same purpose as JSONP, but is more powerful than JSONP. JSONP only supports
GET requests, CORS supports all types of HTTP requests. The advantage of JSONP is that it supports older browsers and can request data from websites that do not support CORS.