What the hell is cross-domain, do you understand?

2021.11.08

Cross-domain is a common topic. Recently, no matter when you are in conjunction with the back-end or micro-front-end, you will encounter it. Just write an article to summarize it.


Cross-domain is a common topic. Recently, no matter when you are in conjunction with the back-end or micro-front-end, you will encounter it. Just write an article to summarize it.

 

What is cross-domain

"Cross-domain" here refers to resource access between different sources. As long as the requested url is different from the following, it belongs to "cross-domain":

    • Protocol: http, https, ...

    • Domain name

    • Port


Some people may think that my own website must only access my own server, and it must be deployed on a domain name.

 

But sometimes, a webpage may need to connect multiple back-end services: one for payment, and one for user information. The backend of each group may have its own domain name. In such scenarios, cross-domain is very common.

 

Why is there cross-domain

The "cross-domain" problem we often talk about is actually talking about the restriction of "cross-domain" access. I believe everyone is accustomed to the following error reports:


This "cross-domain" restriction is actually the browser's built-in security mechanism. Only when a cross-domain request operation occurs on the browser, the browser will automatically throw the above error.

 

Note that this restriction only appears on the browser. If you use Postman tools to access URLs, there is no "cross-domain" restriction. After all, Postman doesn't even have a domain name, so there is no "cross-domain".

 

CORS

Although browsers have restricted “cross-domain” access for security reasons, there will inevitably be the need for access to resources from different sources during development. Therefore, the W3C has developed CORS (Cross-origin resource sharing) mechanism.

Many people have always thought that CORS = cross-domain. In fact, CORS is a solution to "cross-domain".

 

It should be noted that CORS is a "new" protocol (at least new to the previous IE7), which requires not only browser support, but also back-end server support.

 

There is nothing to say about browser support, but whether the browser version supports it:


Then the back-end server supports it. The server needs to add the Access-Control-xxx-yyy field to the Response Header, and the browser can recognize it before it can release the request. For example, the most common one is to add the return header Access-Control-Allow-Origin and set the value to the domain name that needs to be allowed.

 

Simple request VS non-simple request

Browsers divide CORS requests into simple requests and non-simple requests.

 

A simple request will automatically add the Origin field to the HTTP request header when it is sent to indicate which source (protocol + domain name + port) it is currently, and the server will decide whether to let it go.

 

For non-simple requests, an OPTIONS pre-check request will be sent to the server first, and when it passes, a normal CORS request will be sent.

 

For simple requests, the request method is one of the following three:

·         Head

·         Post

·         Get

 

And the HTTP request header field cannot exceed the following fields:

·         Accept

·         Accept-Language

·         Content-Language

·         Last-Event-ID

·         Content-Type

 

At the same time Content-Type can only have three values:

 

application/x-www-form-urlencoded corresponds to ordinary forms

Multipart/form-data corresponding file upload

text/plain corresponds to text sending (generally not very useful)

 

As long as the above conditions are not met, it is a non-simple request. Many people may naturally think that POST requests are non-simple requests, because we often see OPTIONS sent first when POST is sent. In fact, because we generally pass data in JSON format, and the Content-Type is application/json, such POST requests are non-simple requests.

 

Access-Control-xxx-yyyy

When the CORS request is a simple request, the request will detect the following fields in the returned header:

              Access-Control-Allow-Origin: Specify which sources can share resources (including protocol, domain name, and port).

            • Access-Control-Allow-Credentials: When the request needs to carry cookies, this field needs to be true to allow cookies to be carried.

            • Access-Control-Expose-Headers: Because 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 need to                 specify them here.

 

When the CORS request is a non-simple request, the browser will first send an OPTIONS preflight request, which will check the following fields:

            • Access-Control-Request-Method: Specify accessible methods. For non-simple requests, RESTful methods such as PUT, PATCH, and DELETE may be used, and the server needs to add these method names as well.

            • Access-Control-Request-Headers: Specify additional information that will be added to the HTTP request header. A very common scenario is that the backend sometimes puts some environmental parameters in the request header. If this field is not used to specify the allowed fields, then "cross-domain" restrictions will appear.

 

If the OPTIONS request does not pass the server verification, a normal HTTP request will be returned without the CORS return information, so the browser will recognize it as "cross-domain".

 

In summary, when the Console reports an error, you can add which field to the server's return header.

 

CORS middleware

No matter for Express or KOA, we don't need to manually add the above fields anymore. You can add the above fields easily by directly adding a cors middleware, and it is more elegant to write:

1.            var cors = require('cors'); 

2.             

3.            var corsOptions = { 

4.              origin: function (origin, callback) { 

5.                // db.loadOrigins is an example call to load 

6.                // a list of origins from a backing database 

7.                db.loadOrigins(function (error, origins) { 

8.                  callback(error, origins) 

9.                }) 

10.           } 

11.        

12.          

13.         app.use('/', cors(corsOptions), indexRouter); 

 

JSONP

What about browsers that do not support CORS? Although it is unlikely at the moment, how do you solve cross-domain in an era when there is no CORS? The answer is JSONP.

 

Its principle is also very simple: Although browsers restrict HTTP cross-domain requests, there are no restrictions on cross-domain requests for obtaining script tag content.

 

When we insert a <script src="xxx.com"> tag, we will send a GET request to get xxx.com, and there is no "cross-domain" restriction on this GET request. This method can solve the problem of cross-domain The domain problem.

 

Server-side implementation:

        

1.     router.get('/', (req, res) =>  { 

2.    const { callback_name } = req.query; 

3.   res.send(`${callback_name}('hello')`) // 返回 JS 代码,调用 callback_name 这个函数,并传入 hello 

4.                }); 

前端实现:

1.    function jsonpCallback(params) { 

2.      alert('执行 public/index.html 里定义的 jsonpCallback 函数,并传入' + params + '参数'); 

3.   

4.     

5.     

6.    const jsonp = async () => { 

7.      // 制作 script 标签 

8.      const script = document.createElement('script'); 

9.      script.type = 'text/javascript'

10.   script.src = 'http://localhost:9000/user?callback_name=jsonpCallback' 

11.   // 添加标签 

12.   document.body.appendChild(script); 

13.   // 拿到数据再移除 

14.   document.body.removeChild(script); 

15.

16.  

17. jsonp(); 

 

When the jsonp function is called, a script tag is automatically created, and the request is placed in scr, and a GET request is automatically initiated. The server will directly return a string of JavaScript code, and then the front-end executes this JS code obtained from the server to obtain the back-end data.

 

Cross-domain scenarios

"Cross-domain" not only exists in interface access, but also in the following scenarios:

  • The front-end accesses cross-domain URLs. The most common scenario requires the back-end to add the return field of cors
  • Micro front end: There may be "cross-domain" operations in resource access between the main application and sub-applications, and cors needs to be added to the sub-application/main application
  • Login redirection: It's essentially the same as the first one, but it's not the same at the phenomenon level. For example, when accessing abc.com, some websites will be redirected to their login page passport.abc.com. If passport.abc.com does not have cors set, cross-domain

 

Summarize

In general, what we often call "cross-domain" is actually the restrictions imposed by the browser itself when accessing resources from different sources (protocol + domain name + port).

 

In the past, developers would use JSONP to solve cross-domain by generating a script tag and automatically initiating a GET request, but this method is very insecure and is not recommended.

 

Up to now, browsers have perfectly supported the CORS mechanism, just add the corresponding return header Access-Control-xxx-yyy on the server side. When the browser reports a "cross-domain" error, which field is missing, just configure which field on the server side.

 

When developing on the Node side, we can directly use the cors middleware to configure, instead of handwriting to return the fields in the header.