Categories
Uncategorized

A thorough understanding of the principles of cross-domain CORS

background

End of the separation of front-end development model of development is now front and back, is not homologous to get the data, so the cross-domain problem is particularly common in our daily development. In fact, this search also a lot of information online, but it is not comprehensive enough, not enough to understand them thoroughly. This article on a specific combination of sample code and sharing before the PPT to integrate the principles of cross-domain comb it again.

Cross-domain basic concepts

What is cross-domain, when to produce cross-domain, I believe we are all aware of. Let’s here a long story short.

Do not think I’m exaggerating, I have to emphasize, emphasize, emphasize! ! ! ^ _ ^

To a certain browser security factors, increased same-origin policy. Operating contrary to the same-origin policy is prohibited, this occurs when we are talking about cross-domain. What happens if there is no same-origin policy? This is fun.

Oh, the request sent out, the data did not come back. **

Broad cross-domain

In fact, the browser loads of resources many of which are cross-domain, just load the browser that some resources are allowed.

Images, CSS, Script and other resources are not subject to the same origin policy restrictions.

Narrow cross-domain

We are talking about cross-domain main talking ajax request could not be completed.

Cross-domain solutions

There are many cross-domain solutions, and seeks out a bunch. But only a few are common. Some programs can understand how it would look under it.

Old JSONP

JSONP advantage is that because he is old enough to be compatible with a variety of browsers, without compatibility problems, everyone is equal.

He was not sent ajax request, but to use the script tag to load mechanism. Ajax not sending his request.

A picture is worth a thousand words ah.

Since the mechanisms we already know. That we look at the implementation.

Client code


function jsonp() {
    var script = document.createElement('script');
    script.type = 'text/javascript';

    // 传参并指定回调执行函数为backFn
    script.src = 'http://localhost:8100/getUserInfo?uid=100&callback=backFn';
    document.head.appendChild(script);
}

// 回调执行函数
function backFn(res) {
    alert(JSON.stringify(res));
}

document.getElementById('btn_get_data').addEventListener('click',()=>{
    jsonp();
});

Server code

let uid = ctx.query.uid;
let callback=ctx.query.callback;
ctx.body = 'backFn({"code": 0, "user": "admin"})';

The code is simple, not to say.

JSONP shortcomings

Supports only get, but there are security issues.

Technology development so far, jsonp this way before and after the end of the coupling it must be replaced.

CORS cross-domain solutions

January 2014 No. 16 CORS expansion as part of the official release http protocol, mainly defines the communication mechanisms client and server, the so-called agreement.

Figure deepen understanding

CORS from the specific code, it is rather easy to implement, the front end is almost no need to write any code support. Mainly configured on the server. But also a variety of request methods, request a variety of data types are supported perfectly.

CORS need to support both browser and server. All current browsers support this feature, IE browser can not be less than IE10.

CORS entire communication process, the browser is done automatically, without user intervention. For developers, there is no difference AJAX communication CORS communicate with homologous, exactly as it was. Once AJAX browser cross-origin request, it will automatically add some additional header information, and sometimes more than a request for additional time, but users do not have feelings.

Therefore, communication is the key to achieving CORS server. CORS long as the server implements the interface, you can communicate across the source.

Two CORS request

CORS browser requests into two categories: a simple request (simple request) and non-simple request (preflight request) (not-so-simple request).

As long as both of the following two conditions belong to a simple request.

(1) 请求方法是以下三种方法之一:

HEAD
GET
POST

(2)HTTP请求头信息不超出以下几种字段:

Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain

Who do not meet the above two conditions, it is non-simple request.

Browsers handle both of these requests, it is not the same.

CORS simple request

For a simple request, the browser sent directly CORS request. Specifically, it is the first information, the addition of a Origin field.

Here is an example of cross-source browser found this AJAX request is a simple request, automatically in the first information, the Origin add a field.

GET /cors HTTP/1.1 
Origin: http://m.xin.com
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0…

The above header information, Origin field is used to illustrate, which source (port protocol name + +) from this request. Server based on this value, the decision whether to grant the request.

If Origin specified source, not within the scope of the license, the server returns a normal HTTP response. Browser found this response header information does not include Access-Control-Allow-Origin field (see below), you know wrong, so throw an error, is the XMLHttpRequest onerror callback function to capture. Note that this error code is not recognized by the state, because the HTTP response status code might be 200.

If Origin domain name specified in the license range, response returned by the server, a few extra header field.

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

The above header information, the three of CORS request related fields, are beginning to Access-Control-.

(1)Access-Control-Allow-Origin

This field is required. Its value is either the value of the field Origin request either a *, any request for acceptance of the domain name.

(2)Access-Control-Allow-Credentials

This field is optional. Its value is a Boolean value that indicates whether to allow sending Cookie. By default, Cookie CORS not included in the request. Set to true, it means that the server explicit permission, Cookie can be included in the request sent to the server. This value can only be set to true, if the server is not sent by the browser Cookie, you can delete the field.

(3)Access-Control-Expose-Headers

This field is optional. When the request is CORS, getResponseHeader XMLHttpRequest object () method to get only six basic fields: Cache-Control, Content-Language, Content-Type, Expires, Last-Modified, Pragma. If you want to get the other fields must be specified in the Access-Control-Expose-Headers inside. The above example specifies, getResponseHeader ( ‘FooBar’) can return a value FooBar field.

withCredentials property

Speaking of the above, CORS request not to send default HTTP Cookie and authentication information. If you want Cookie to the server, the server agree on the one hand, specify the Access-Control-Allow-Credentials field.

Access-Control-Allow-Credentials: true

On the other hand, the developer must open withCredentials properties AJAX request.

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

Otherwise, even if the server agree to send Cookie, the browser will not be sent. Alternatively, the server requirements set Cookie, the browser will not be processed.

However, if you omit withCredentials set, some browsers will send Cookie together. In this case, explicitly close withCredentials.

xhr.withCredentials = false;

Note that, if you want to send Cookie, Access-Control-Allow-Origin can not be set to an asterisk, you must specify clear, consistent with the domain name requested web page. Meanwhile, Cookie still follow the same-origin policy, only with Cookie domain name server settings will be uploaded, Cookie and other domain names will not upload, and (cross-source) the original page code can not be read document.cookie under the domain name server Cookie.

CORS simple request code reference

Simple request processing client does not need to do anything, just to show the processing server needs to be done.

Server-side code written using Node koa

    ctx.set('Access-Control-Allow-Origin', 'http://localhost:3000');
            ctx.set('Access-Control-Allow-Credentials','true');
            body.data={
                carId:100,
                carName:'宝马x5-1000'
            };

In addition you can try to pass on their cookie

CORS non-simple request – preflight request

Request is a non-simple that there is a request to the server special requirements, such as the DELETE or PUT request method is, or the type of field Content-Type is application / json.

Non-simple request CORS request, before the official communication, increase an HTTP query request, called “preflight” request (preflight).

The browser first asks the server, where the domain of the current web page whether in the license server list, and which HTTP verbs can and header field use. Only positive response, the browser will issue a formal request XMLHttpRequest, otherwise an error.

Figure understand

The following is a JavaScript script for a browser.

var url = 'http://api.uxin.com/user';
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 sends a custom header X-Custom-Header.

The browser sees that this is a non-simple request, it automatically sends a “preflight” request to the server can confirm this request. The following is the HTTP header “preflight” request.

OPTIONS /cors HTTP/1.1
Origin: http://m.a.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…

“Preflight” request using a request method OPTIONS, showing the request is used to query. Head inside information, key fields is Origin, which represents a request from the source.

Origin field addition, the header information “preflight” requests comprises two special fields.

(1)Access-Control-Request-Method

This field is required for lists of CORS browser HTTP request method which will be used, the embodiment is PUT.

(2)Access-Control-Request-Headers

This field is a comma-separated string that specifies the browser request CORS extra header field transmitted, the examples are X-Custom-Header.

CORS preflight request response

Server receives a “pre-screening” after the request, checks the Origin, after the Access-Control-Request-Method and Access-Control-Request-Headers field to verify that allow cross-origin requests, we 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://m.a.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

The above HTTP response, the key is the Access-Control-Allow-Origin field representing http://m.a.com can request data. This field can be set to an asterisk, it agreed any cross-origin requests.

Access-Control-Allow-Origin: *

If the browser denied “preflight” request, it returns a normal HTTP response, but no related CORS header field. In this case the browser will identify the server does not agree preflight request, thus triggering an error is caught onerror callback function XMLHttpRequest object. The console will print out the following error message.

XMLHttpRequest cannot load http://m.a.com.
Origin http://m.a.com is not allowed by Access-Control-Allow-Origin.

Server response CORS other relevant fields below.

Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: X-Custom-Header
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 1728000

(1)Access-Control-Allow-Methods

This field is required, its value string is a comma-separated cross-domain requests indicating that all methods that the server supports. Note that the return of all supported methods, rather than simply the method that the browser requests. This is to avoid multiple “preflight” request.

(2)Access-Control-Allow-Headers

When the browser requests include Access-Control-Request-Headers field of the Access-Control-Allow-Headers field is required. It is also a comma delimited string indicating the server supports all the header field is not limited to a browser request field in the “pre-screening” in.

(3)Access-Control-Allow-Credentials

The same meaning in the field with a simple request.

(4)Access-Control-Max-Age

This field is optional pre-screening is used to specify the current valid request, in seconds. Above results, the period is 20 days (1,728,000 seconds), allowing the cache to respond to the article 1728000 seconds (i.e., 20 days), during which the preflight not issue another request.

Normal request and response CORS browser

Once the server through a “preflight” request, after each time the browser requests a normal CORS, as it related to a simple request, there will be a Origin header field. In response to the server, you will also have an Access-Control-Allow-Origin header field.

Here it is after “preflight” request, normal CORS browser requests.

PUT /cors HTTP/1.1
Origin: http://m.a.com
Host: api.alice.com
X-Custom-Header: value
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0..

Origin field in the header information above the browser is automatically added.

The following is a normal server response.

Access-Control-Allow-Origin: http://m.a.com
Content-Type: text/html; charset=utf-8

The above header information, Access-Control-Allow-Origin field is contained in each response are bound.

CORS preflight request code reference

Code uses Node koa achieve

  //OPTIONS 请求查询服务器的性能,或者查询与资源相关的选项和需求
            ctx.set('Access-Control-Allow-Credentials', 'true');
            ctx.set('Access-Control-Allow-Methods','PUT');
            ctx.set('Access-Control-Allow-Origin', 'http://localhost:3000');
            ctx.set('Access-Control-Allow-Headers', 'content-type');
            ctx.set('Access-Control-Max-Age','100');
            body.data = {
                carId: 100,
                carName: '宝马x5'
            }

CORS compatible case

CORS support IE10 +, IE8,9 need to use ie proprietary api – use XDomainRequest object to support cors.

Note: ie at localhost: 8000 = localhost: 8001 = localhost as the same domain, so as not to step on when local test pit.

CORS summary

We want to know CORS is part of the http protocol, done by the browser and the server. So for the front-end, it is quite simple. We have to do is understand the agreement and implementation mechanism, you can quickly locate in the face of similar problems.

More cross-domain processing scheme

Many cross-domain solutions, the most common way to CORS. The figure the seven students who are interested can continue to study.

Reference material

https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS

https://segmentfault.com/a/1190000011145364

http://www.ruanyifeng.com/blog/2016/04/cors.html

Leave a Reply