CORS explained in detail
CORS is a W3C standard, the full name is Cross-origin resource sharing.
It allows the browser to cross-origin server, issued
XMLHttpRequest/fetch request, thus overcoming the AJAX can only be used in the same source of the limitations.
CORS requires both browser and server support. Currently, all browsers support this feature, and Internet Explorer cannot be lower than IE10.
The entire CORS communication process is done automatically by the browser, without user involvement. For developers, CORS communication with the same source of AJAX communication no difference, the code is exactly the same. Once the browser finds the AJAX request cross-source, it will automatically add some additional headers, and sometimes one more additional request, but the user will not feel it.
Therefore, the key to achieve CORS communication is the server. As long as the server implements the CORS specification, it can communicate across sources.
2. Two types of requests
Browsers divide CORS requests into two categories: simple requests and not-so-simple requests.
As long as the following two conditions are met, it is a simple request.
The request method is one of the following three methods.
The HTTP headers do not exceed the following fields.
- Content-Type: limited to three values
This is to be compatible with forms, because historically forms have been able to send cross-domain requests. AJAX’s cross-domain design is that, as long as the form can send, AJAX can send directly.
Where the above two conditions are not met at the same time, it is not a simple request.
The browser processing of these two requests, is not the same.
3. Simple request
3.1 Basic flow
For a simple request, the browser makes a CORS request directly. Specifically, it adds an
Origin field to the header.
Here is an example, the browser finds that the cross-origin AJAX request is a simple request, it automatically adds an
Origin field to the header information.
In the above header, the
Origin field is used to indicate the source (protocol + domain + port) from which this request is coming. Based on this value, the server decides whether to grant the request or not.
If the source specified by
Origin is not within the scope of the permission, the server returns a normal HTTP response. The browser finds that this response does not contain the
Access-Control-Allow-Origin field in its headers (see below for details) and knows that there is an error, thus throwing an error that is caught by the
onerror callback function of
XMLHttpRequest. Note that such errors cannot be identified by status codes, as the status code of an HTTP response can be 200.
If the domain name specified by
Origin is within the permitted range, the server returns a response with a few extra header fields.
The above header contains three fields related to CORS requests, all starting with
This field is required. Its value is either the value of the
Originfield at the time of the request, or a
*that indicates that a request for an arbitrary domain name is accepted.
This field is optional. Its value is a boolean indicating whether cookies are allowed to be sent, and by default, cookies are not included in CORS requests. A value of
truemeans that the server has explicitly given permission for the cookie to be included in the request and sent to the server together. This value can also only be set to
true, so if the server does not want the browser to send cookies, just delete the field.
This field is optional. CORS request, the
getResponseHeader()method can only get six basic fields:
Pragma. If you want to get other fields, you must specify them in the
Access-Control-Expose-Headers. In the above example,
getResponseHeader('FooBar')will successfully get the value of the
The wildcard character:
*, proposed in the latest specification, indicates that the client is allowed to access all header. is not yet implemented in some browsers.
3.2 withCredentials property
As mentioned above, CORS requests do not send cookies and HTTP authentication information by default. If a cookie is to be sent to the server, on the one hand, the server has to agree to respond to the
On the other hand, the developer must turn on the
withCredentials property in the AJAX request
Otherwise, even if the server agrees to send a cookie, the browser will not send it. Or, if the server asks to set a cookie, the browser will not handle it.
However, some browsers will still send cookies together if the
withCredentials setting is omitted, in which case
withCredentials can be turned off explicitly.
Note that to send a cookie,
Access-Control-Allow-Origin cannot be set to an asterisk, but must specify a domain name that is explicit and consistent with the requested page. At the same time, cookies still follow the same origin policy, only cookies set with the server domain will be uploaded, cookies from other domains will not be uploaded, and the
document.cookie in the (cross-origin) original web code will not be able to read cookies from the server domain.
4. Non-simple requests
4.1 Preflight Requests
A non-simple request is one that has special requirements for the server, such as a request method of
DELETE, or a
Content-Type field of type
A CORS request that is not a simple request adds an HTTP query request, called a preflight, before the formal communication.
The browser first asks the server if the domain name of the current web page is in the server’s permission list, and which HTTP verbs and header fields can be used. Only when it gets a positive answer does the browser issue a formal
XMLHttpRequest request, otherwise it throws an exception.
In the above code, the HTTP request method is
PUT and sends a custom header
The browser finds that this is a non-simple request and automatically issues a “preflight” request to ask the server to confirm that it can do so. Here is the HTTP header for this “preflight” request.
The request method used for the “preflight” request is
OPTIONS, which indicates that the request is for interrogation. Inside the header, the key field is
Origin, which indicates the source of the request.
In addition to the
Origin field, the header of a “preflight” request includes two special fields.
This field is required to list which HTTP methods will be used by the browser’s CORS request, in the above example
This field is a comma-separated string that specifies the additional header field that will be sent by the browser CORS request, in the above example
4.2 Response to Preflight Requests
After the server receives the Preflight request, it checks the
Access-Control-Request-Headers fields and confirms that cross-origin requests are allowed, then it can respond.
The key thing in the HTTP response above is the
Access-Control-Allow-Origin field, which indicates that
http://api.bob.com is allowed to initiate the request. This field can also be set to an asterisk to indicate consent to any cross-origin request.
If the server denies the preflight request, a normal HTTP response is returned, but without any CORS-related header fields. At this point, the browser determines that the server did not agree to the preflight request and therefore triggers an error that is caught by the
onerror callback function of the
XMLHttpRequest object. The console will print the following error message.
The other CORS-related fields that the server responds to are listed below.
This field is required and its value is a comma-separated string indicating all methods supported by the server for cross-domain requests. Note that all supported methods are returned, not just the one requested by the browser. This is to avoid multiple “preflight” requests.
Access-Control-Allow-Headersfield is required if the browser request includes the
Access-Control-Request-Headersfield. 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 the case of a simple request.
This field is optional and is used to specify the validity of this preflight request in seconds. In the above result, the validity period is 20 days (1728000 seconds), which means that the response is allowed to be cached for 1728000 seconds (i.e. 20 days), during which time another preflight request does not have to be issued.
4.3 Normal browser request and response
Once the server has passed the “preflight” request, each subsequent normal browser CORS request will have an
Origin header field, just like a simple request. The server’s response will also have an
Access-Control-Allow-Origin header field.
Here is the normal CORS request from the browser after the “preflight” request.
Origin field in the above header is automatically added by the browser.
Here is the normal response from the server.
In the above header, the
Access-Control-Allow-Origin field is always included in every response.
CORS is used for the same purpose as JSONP, but is more powerful than JSONP. JSONP only supports
GETrequests, while CORS supports all types of HTTP requests. the advantages of JSONP are support for older browsers and the ability to request data from sites that do not support CORS.
Spring With CORS
spring provides a number of ways to implement
CORS can be easily implemented using the
@CrossOrigin annotation. The code is as follows.
Note that When
allowedOrigins cannot contain the special value
* because it cannot be set in the
Access-Control-Allow-Origin response header. To allow credentials from a set of sources, list them explicitly or consider using
Otherwise, an exception will be thrown when the application starts.
Global CORS configuration can be done through the
addCorsMappings method of the
WebMvcConfiguration configuration interface.
allowedOrigins cannot be
CorsFilter is specifically designed to handle CORS requests. This approach is the most flexible and allows you to write code to handle CORS requests.