web123456

9 common front-end cross-domain solutions (detailed explanation)

Article reprinted from:9 common front-end cross-domain solutions (detailed explanation)_MOOC Notes ()

1. What is cross-domain?

In the front-end field, cross-domain means that the browser allows the sending of cross-domain requests to the server, thus overcoming Ajax's onlyHomogenousLimitations of use.

What is a homologous strategy?

  Same Origin PolicyIt is a convention, introduced by Netscape in 1995. It is the most core and basic security function of the browser. If the same-origin policy is missing, the browser is vulnerable to attacks such as XSS and CSFR. The so-called homologous origin refers to the same "protocol + domain name + port". Even if two different domain names point to the same IP address, they are not homologous.

The same-origin policy restricts the following behaviors:

  • Cookies, LocalStorage, and IndexDB cannot be read
  • DOM and JS objects cannot be obtained
  • AJAX request cannot be sent

2. Common cross-domain scenarios

URL illustrate Whether to allow communication
Website Domain Names, Online Stores & Hosting -
Website Domain Names, Online Stores & Hosting -
Website Domain Names, Online Stores & Hosting - lab/
Same domain name, different files or paths allow
:8000/
/
Same domain name, different ports Not allowed
http:///
https:///
Same domain name, different protocols Not allowed
http:///
http://192.168.4.12/
Domain name and domain name correspond to the same ip Not allowed
http:///
http:///
http:///
The main domain is the same, the subdomain is different Not allowed
http:///
http:///
Different domain names Not allowed

3. 9 cross-domain solutions

1. JSONP cross-domain

  jsonpThe principle is to use<script>There is no cross-domain restriction for tags, through<script>Tag the src attribute, sends a GET request with callback parameter, the server pieces the interface return data into the callback function, returns it to the browser, and the browser parses and executes, so that the front-end gets the data returned by the callback function.

1) Native JS implementation:

<script>
     var script = ('script');
      = 'text/javascript';

     // Pass a callback function name to the backend, so that the backend can execute the callback function defined in the frontend when returning
      = 'http://:8080/login?user=admin&callback=handleCallback';
     (script);

     // Callback execution function
     function handleCallback(res) {
         alert((res));
     }
  </script>

The server returns the following (the global function is executed when it returns):

handleCallback({"success": true, "user": "admin"})

2) jquery Ajax implementation:

$.ajax({
     url: 'http://:8080/login',
     type: 'get',
     dataType: 'jsonp', // The request method is jsonp
     jsonpCallback: "handleCallback", // Custom callback function name
     data: {}
 });

3) Vue axios implementation:

this.$http = axios;
this.$('http://:8080/login', {
    params: {},
    jsonp: 'handleCallback'
}).then((res) => {
    (res); 
})

Backend code:

var querystring = require('querystring');
 var http = require('http');
 var server = ();

 ('request', function(req, res) {
     var params = (('?')[1]);
     var fn = ;

     // jsonp return settings
     (200, { 'Content-Type': 'text/javascript' });
     (fn + '(' + (params) + ')');

     ();
 });

 ('8080');
 ('Server is running at port 8080...');

Disadvantages of jsonp: Only one kind of request can be sent.

2. Cross-domain resource sharing (CORS)

  CORSIt is a W3C standard, with the full name "Cross-origin resource sharing".
It allows the browser to issue XMLHttpRequest requests to cross-origin servers, thus overcoming the limitation that AJAX can only be used in the same origin.
CORS requires both browser and server support. Currently, all browsers support this function, and IE browser cannot be lower than IE10.

The browser divides CORS cross-domain requests into simple requests and non-simple requests.

As long as two conditions are met at the same time, it is a simple request

(1) Use one of the following methods:

  • head
  • get
  • post

(2) The requested Heder is

  • Accept
  • Accept-Language
  • Content-Language
  • Content-Type: Only limited to three values: application/x-www-form-urlencoded, multipart/form-data, text/plain

If the above two conditions are not met at the same time, it is a non-simple request. The browser's handling of these two types is different.

Simple request

For simple requests, the browser directly issues CORS request. Specifically, add an Origin field to the header information.

GET /cors HTTP/1.1
Origin: 
Host: 
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...

In the header information above, the Origin field is used to indicate which source the request comes from (protocol + domain name + port). Based on this value, the server decides whether to agree to the request.

The response header fields set by CORS requests all start with Access-Control-:

1)Access-Control-Allow-Origin: Must-choose

Its value is either the value of the Origin field at the time of request, or it is a *, indicating that the request for any domain name is accepted.

2)Access-Control-Allow-Credentials: Optional

Its value is a Boolean value, indicating whether to allow the sending of cookies. By default, cookies are not included in CORS requests. Set to true, which means the server explicitly allows it, and the cookies can be included in the request and sent to the server together. This value can only be set to true. If the server does not send cookies by the browser, delete the field.

3)Access-Control-Expose-Headers: 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, and 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 FooBar field.

No simple request

Non-simple requests are requests that have special requirements for the server, such as the request method is PUT or DELETE, or the type of the Content-Type field is application/json. A CORS request that is not a simple request will add an HTTP query request before the official communication, which is called a "preflight" request.

Pre-check request

The request method used for pre-flight request is OPTIONS, which means that the request is used to inquire. In the request 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 "pre-flight" request includes two special fields.

OPTIONS /cors HTTP/1.1
Origin: 
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Custom-Header
Host: 
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0..

1)Access-Control-Request-Method: Must-choose

What HTTP methods will be used to list the browser's CORS request? The above example is PUT.

2)Access-Control-Request-Headers: Optional

This field is a comma-separated string, specifying the additional header information field sent by the browser CORS request. The above example is X-Custom-Header.

Response to pre-check requests

After the server receives the "preflight" request, after checking the Origin, Access-Control-Request-Method and Access-Control-Request-Headers fields, confirm that cross-origin requests are allowed, and you can respond.

In HTTP response, in addition to the key is the Access-Control-Allow-Origin field, other CORS-related fields are as follows:

1)Access-Control-Allow-Methods: Must-choose

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 one requested by the browser. This is to avoid multiple "preflight" requests.

2)Access-Control-Allow-Headers

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 that all header fields supported by the server are not limited to fields requested by the browser in "Preflight".

3)Access-Control-Allow-Credentials: Optional

This field has the same meaning as when requesting it.

4)Access-Control-Max-Age: Optional

Used to specify the validity period of this pre-check request, in seconds.

CORS cross-domain example

1) Front-end settings

  • Native ajax:
var xhr = new XMLHttpRequest(); // IE8/9 requires compatibility

 // Whether the front-end settings include cookies
  = true;

 ('post', 'http://:8080/login', true);
 ('Content-Type', 'application/x-www-form-urlencoded');
 ('user=admin');

  = function() {
     if ( == 4 && == 200) {
         alert();
     }
 };
  • jquery ajax:
$.ajax({
     ...
    xhrFields: {
        withCredentials: true // Whether to set the front-end with cookies
    },
    crossDomain: true, // Will include additional information across domains in the request header, but will not contain cookies
     ...
 });

2) Server settings

  • nodejs code
var http = require('http');
 var server = ();
 var qs = require('querystring');

 ('request', function(req, res) {
     var postData = '';

     // Data block is being received
     ('data', function(chunk) {
         postData += chunk;
     });

     // The data is received
     ('end', function() {
         postData = (postData);

         // Cross-domain background settings
         (200, {
             'Access-Control-Allow-Credentials': 'true', // The backend allows sending cookies
             'Access-Control-Allow-Origin': 'http://', ​​// The domain allowed to access (protocol + domain name + port)
             /*
              * The cookie set here is still domain2 rather than domain1, because the backend cannot write cookies across domains (the nginx reverse proxy can be implemented).
              * But as long as a cookie authentication is written in domain2, the subsequent cross-domain interfaces can obtain cookies from domain2, so that all interfaces can be accessed across domains.
              */
             'Set-Cookie': 'l=a123456;Path=/;Domain=;HttpOnly' // The function of HttpOnly is to prevent js from reading cookies
         });

         ((postData));
         ();
     });
 });

 ('8080');
 ('Server is running at port 8080...');

3. nginx proxy cross-domain

nginx proxy cross-domain, essentially the same as CORS cross-domain principle, set the request response header through configuration filesAccess-Control-Allow-Origin…etc.

1) nginx configuration solves iconfont cross-domain

The browser's cross-domain access to regular static resources such as js, css, img is licensed by the same-origin policy, but the iconfont font file (eot|otf|ttf|woff|svg) is exception. At this time, the following configuration can be added to the static resource server of nginx.

location / {
  add_header Access-Control-Allow-Origin *;
}

2) nginx reverse proxy interface cross-domain

Cross-domain issue: Same-origin policies are only security policies for browsers. The server-side calls the HTTP interface only using the HTTP protocol, and does not require a same-origin policy, so there is no cross-domain problem.

Implementation idea: Configure a proxy server through Nginx to configure the domain name and domain1, and use different ports as a springboard machine, reverse proxy accesses the domain2 interface, and can modify the domain information in the cookie by the way, so as to facilitate the writing of the current domain cookie and achieve cross-domain access.

nginx specific configuration:

#proxy server
 server {
     listen 81;
     server_name ;

     location / {
         proxy_pass http://:8080; #Reverse proxy
         proxy_cookie_domain; #Modify the domain name in the cookie
         index ;

         # When accessing nignx using webpack-dev-server and other middleware proxy interfaces, there is no browser participation at this time, so there is no homologous restriction. The following cross-domain configurations cannot be enabled.
         add_header Access-Control-Allow-Origin http://; # When the current end only cross-domain without cookies, it can be *
         add_header Access-Control-Allow-Credentials true;
     }
 }

4. Nodejs middleware agent cross-domain

The node middleware implements cross-domain proxy, and the principle is roughly the same as nginx. It all enables a proxy server to forward data. You can also modify the domain name in the cookie in the response header by setting the cookieDomainRewrite parameter to realize cookie writing in the current domain, which facilitates interface login authentication.

1) Cross-domain of non-vue frameworks

Use node + expression + http-proxy-middleware to build a proxy server.

  • Front-end code:
var xhr = new XMLHttpRequest();

 // Front-end switch: Does the browser read and write cookies
  = true;

 // Access the http-proxy-middleware proxy server
 ('get', 'http://:3000/login?user=admin', true);
 ();
  • Middleware server code:
var express = require('express');
 var proxy = require('http-proxy-middleware');
 var app = express();

 ('/', proxy({
     // Agent cross-domain target interface
     target: 'http://:8080',
     changeOrigin: true,

     // Modify response header information, implement cross-domain and allow cookies
     onProxyRes: function(proxyRes, req, res) {
         ('Access-Control-Allow-Origin', 'http://');
         ('Access-Control-Allow-Credentials', 'true');
     },

     // Modify the cookie domain name in the response information
     cookieDomainRewrite: '' // Can be false, indicating that no modification
 }));

 (3000);
 ('Proxy server is listen at port 3000...');

2) Cross-domain of vue framework

The project built by node + vue + webpack + webpack-dev-server requires cross-domain interfaces and directly modify the configuration. In the development environment, the vue rendering service and interface proxy service are the same as webpack-dev-server, so the page and the proxy interface are no longer cross-domain.

Some configurations:

= {
     entry: {},
     module: {},
     ...
     devServer: {
         historyApiFallback: true,
         proxy: [{
             context: '/login',
             target: 'http://:8080', // Agent cross-domain target interface
             changeOrigin: true,
             Secure: false, // Used when a proxy https service reports an error
             cookieDomainRewrite: '' // Can be false, indicating that no modification
         }],
         noInfo: true
     }
 }

5. + iframe cross-domain

This solution is only available for cross-domain application scenarios where the main domain is the same and the subdomain is different. Implementation principle: Both pages are forced to be set as the basic main domain through js, and the same domain is implemented.

1) Parent window: (/)

<iframe  src="/"></iframe>
<script>
     = '';
    var user = 'admin';
</script>

1) Sub-window: (/)

<script>
      = '';
     // Get variables in the parent window
     ('get js data from parent ---> ' + );
 </script>

6. + iframe cross-domain

Implementation principle: a and b want to communicate across domains and implement it through the intermediate page c. Three pages, different domains use the Iframe's value to communicate directly between the same domains.

Specific implementation: Domain A: -> Domain B: -> Domain A: Different domains a and b can only communicate in one-way through hash values, and different domains b and c can only communicate in one-way, but c and a are the same domain, so c can access all objects on page a.

1):(http:///)

<iframe src="http:///" style="display:none;"></iframe>
 <script>
     var iframe = ('iframe');

     // Pass hash value to it
     setTimeout(function() {
          = + '#user=admin';
     }, 1000);
    
     // Open callback method to the same domain
     function onCallback(res) {
         alert('data from ---> ' + res);
     }
 </script>

2):(http:///)

<iframe src="http:///" style="display:none;"></iframe>
 <script>
     var iframe = ('iframe');

     // Listen to the hash value and then pass it to
      = function () {
          = + ;
     };
 </script>

3):(http:///)

<script>
     // Listen to the hash value transmitted
      = function () {
         // Then pass the result back by operating the js callback of the same domain
         ('hello: ' + ('#user=', ''));
     };
 </script>

7. + iframe cross-domain

The uniqueness of the attribute: the name value still exists after loading on different pages (or even different domain names), and can support very long name values ​​(2MB).

1):(http:///)

var proxy = function(url, callback) {
     var state = 0;
     var iframe = ('iframe');

     // Load cross-domain page
      = url;

     // The onload event will be fired twice, the cross-domain page will be loaded for the first time, and the data will be stored in
      = function() {
         if (state === 1) {
             // After the second time onload (proxy page in the same domain) is successful, read the data in the same domain
             callback();
             destoryFrame();

         } else if (state === 0) {
             // After the first time onload (cross-domain page) is successful, switch to the same domain proxy page
              = 'http:///';
             state = 1;
         }
     };

     (iframe);

     // After obtaining the data, destroy this iframe and free up memory; this also ensures security (not accessed by other domain frame js)
     function destoryFrame() {
         ('');
         ();
         (iframe);
     }
 };

 // Request cross-domain b page data
 proxy('http:///', function(data){
     alert(data);
 });

2):(http:///)

The intermediate proxy page, as in the same domain, the content is empty.

3):(http:///)

<script>
     = 'This is domain2 data!';
</script>

Through the src attribute of the iframe, the trans-domain data is transferred from the external domain to the local domain from the external domain to the local domain. This cleverly bypasses the browser's cross-domain access restrictions, but at the same time it is a safe operation.

8. PostMessage cross-domain

postMessage is an API in HTML5 XMLHttpRequest Level 2, and is one of the few window properties that can be operated across domains. It can be used to solve the following problems:

  • Data delivery of pages and new windows that it opens
  • Message delivery between multiple windows
  • Page with nested iframe messaging
  • Cross-domain data transmission in the above three scenarios

Usage: The postMessage(data,origin) method accepts two parameters:

  • data: The html5 specification supports any basic type or replicable objects, but some browsers only support strings, so it is best to use () to serialize when passing parameters.
  • origin: Protocol + host + port number, can also be set to "*", indicating that it can be passed to any window, and if you want to specify the same origin as the current window, it is set to "/".

1):(http:///)

<iframe src="http:///" style="display:none;"></iframe>
 <script>
     var iframe = ('iframe');
      = function() {
         var data = {
             name: 'aym'
         };
         // Transfer cross-domain data to domain2
         ((data), 'http://');
     };

     // Accept domain2 to return data
     ('message', function(e) {
         alert('data from domain2 ---> ' + );
     }, false);
 </script>

2):(http:///)

<script>
     // Receive domain1 data
     ('message', function(e) {
         alert('data from domain1 ---> ' + );

         var data = ();
         if (data) {
              = 16;

             // After processing, send back domain1
             ((data), 'http://');
         }
     }, false);
 </script>

9. WebSocket protocol cross-domain

WebSocket protocol is a new protocol for HTML5. It realizes full duplex communication between the browser and the server, and allows cross-domain communication, which is a good implementation of server push technology.
The native WebSocket API is not very convenient to use. When we use it, it encapsulates the webSocket interface well, provides a simpler and more flexible interface, and provides backward compatibility for browsers that do not support webSocket.

1) Front-end code:

<div>user input: <input type="text"></div>
 <script src="//2.2.0/"></script>
 <script>
 var socket = io('http://:8080');

 // The connection is successfully processed
 ('connect', function() {
     // Listen to server messages
     ('message', function(msg) {
         ('data from server: ---> ' + msg);
     });

     // The listening server is closed
     ('disconnect', function() {
         ('Server socket has closed.');
     });
 });

 ('input')[0].onblur = function() {
     ();
 };
 </script>

2) Nodejs socket background:

var http = require('http');
 var socket = require('');

 // Start http service
 var server = (function(req, res) {
     (200, {
         'Content-type': 'text/html'
     });
     ();
 });

 ('8080');
 ('Server is running at port 8080...');

 // Listen to socket connections
 (server).on('connection', function(client) {
     // Receive information
     ('message', function(msg) {
         ('hello:' + msg);
         ('data from client: ---> ' + msg);
     });

     // Disconnect processing
     ('disconnect', function() {
         ('Client socket has closed.');
     });
 });

summary

The above are 9 common cross-domain solutions. jsonp (only supports get requests and supports old IE browsers) is suitable for loading static resources such as js, css, imgs and other domain names; CORS (supports all types of HTTP requests, but does not support browser IE10 or below) is suitable for various cross-domain requests of ajax; Nginx proxy cross-domain and nodejs middleware cross-domain principles are similar, both build a server and directly request HTTP interfaces on the server side, which is suitable for front-end project debugging back-end interfaces separated by front-end projects. +iframe is suitable for cross-domain requests with the same main domain name and different subdomain names. postMessage and websocket are both new features of HTML5, and their compatibility is not very good. They are only suitable for mainstream browsers and IE10+.