Cross domain

What is cross-domain

Cross-domain refers to a document or script in one domain trying to request a resource in another domain. Cross-domain is defined broadly here.

In a broad sense, cross-domain:

2. Resource embedding: <link>, <script>, <img>, <frame> and other DOM tags, as well as background: URL (), @font-face() and other file outer links in styles 3. Script requests: JS-initiated Ajax requests, dom and JS object cross-domain operations, etcCopy the code

In fact, what we usually mean by cross-domain is narrowly defined, a class of request scenarios that are restricted by the browser’s same-origin policy.

What is the same origin policy?

The Same Origin Policy (SOP) is a convention introduced by Netscape into the browser in 1995. It is the core and most basic security function of the browser. Without the Same Origin policy, the browser is vulnerable to XSS and CSFR attacks. Same-origin means that the protocol, domain name, and port are the same. Even if two different domain names point to the same IP address, they are not same-origin.

The same origin policy restricts the following behaviors:

1.) Cookie, LocalStorage, and IndexDB cannot be read. 2.) DOM and Js objects cannot be obtainedCopy the code

Common cross-domain scenarios

URL that whether to allow communication http://www.domain.com/a.js http://www.domain.com/b.js the same domain name, Different file or path to allow http://www.domain.com/lab/c.js http://www.domain.com:8000/a.js http://www.domain.com/b.js the same domain name, Different ports Do not allow the http://www.domain.com/a.js https://www.domain.com/b.js the same domain name, Different protocols Do not allow the http://www.domain.com/a.js http://192.168.4.12/b.js domain names and domain name corresponding to the same IP is not allowed to http://www.domain.com/a.js http://x.domain.com/b.js Same primary domain, Different subdomains Do not allow the different domain name http://domain.com/c.js http://www.domain1.com/a.js http://www.domain2.com/b.js Don't allowCopy the code

Simple definition: as long as the port number before a different belongs to the cross-domain

Demonstrate the cross-domain

server.js

const http = require('http');
const fs = require('fs');
http.createServer((req, res) = > {
    const { url, method } = req;
    if (url === '/' && method === 'GET') {
        // Read the first page
        fs.readFile('./index.html'.(err, data) = > {
            if (err) {
                res.statusCode = 500;// Server internal error
                res.end('500- Interval Serval Error! ');
            }
            res.statusCode = 200;// Set the status code
            res.setHeader('Content-Type'.'text/html'); res.end(data); })}else if (url === '/user' && method === 'GET') {
        res.statusCode = 200;// Set the status code
        res.setHeader('Content-Type'.'application/json');
        res.end(JSON.stringify([{ name: "Little Marco" }]));
    }

}).listen(3000);
Copy the code

Axios initiates the request

axios.get('http://127.0.0.1:3000/user').then(res= > {
    console.log(res.data);

}).catch(err= > {
    console.log(err);

})
Copy the code

Common cross-domain solutions

  1. Cross domains via JSONP
  2. Cross-domain resource sharing (CORS most commonly used)
  3. Nginx agents cross domains
  4. Nodejs middleware proxies cross domains

Except, there are:

  1. Document.domain +iframe (this method can only be used if the primary domain is the same)
  2. Dynamically create script tags (Script tags are not restricted by the same origin policy)
  3. Location. hash + iframe (using location.hash to pass values)
  4. Window.name +iframe (The name value still exists after loading on different pages (even different domain names) and can support very long name values (2MB))
  5. PostMessage (API in XMLHttpRequest Level 2 in HTML5)
  6. Web Sockets (Web Sockets are a browser API whose goal is to provide full-duplex, bidirectional communication over a single persistent connection. (Same-origin policy does not apply to Web Sockets)

Cross domains via JSONP

Usually, in order to reduce the load of the Web server, we separate static resources such as JS, CSS and IMG to another server with an independent domain name, and then load static resources from different domain names in the HTML page through corresponding tags, which are allowed by the browser. Based on this principle, we can dynamically create script. Request a reference url to achieve cross-domain communication

The latest version of Axios no longer supports jSONP methods. Not wanting to invoke another dependency just because of a JSONP request, axios decided to wrap it itself

axios.jsonp = (url) = > {
    if(! url) {console.error('Axios.jsonp requires at least one URL argument! ')
        return;
    }
    return new Promise((resolve, reject) = > {
        window.jsonCallBack = (result) = > {
            resolve(result)
        }
        var JSONP = document.createElement("script");
        JSONP.type = "text/javascript";
        JSONP.src = `${url}callback=jsonCallBack`;
        document.getElementsByTagName("head") [0].appendChild(JSONP);
        setTimeout(() = > {
            document.getElementsByTagName("head") [0].removeChild(JSONP)
        }, 500)})}// The first is through jSONp
axios.jsonp('http://127.0.0.1:3000/user? ')
    .then(res= >{
    console.log(res);
}).catch(err= >{
    console.log(err);

})
Copy the code

server.js

const express = require('express');
const fs = require('fs');
const app = express();
// Middleware methods
// set node_modules to the static resource directory
/ / in the future if you use the SRC attribute in the template at http://localhost:3000/node_modules
app.use(express.static('node_modules'))
app.get('/'.(req,res) = >{
  fs.readFile('./index.html'.(err,data) = >{
    if(err){
      res.statusCode = 500;
      res.end('500 Interval Serval Error! ');
    }
    res.statusCode = 200;
    res.setHeader('Content-Type'.'text/html'); res.end(data); })})// app.set('jsonp callback name', 'cb')
app.get('/api/user'.(req,res) = >{
  console.log(req);
  / / http://127.0.0.1:3000/user? cb=jsonCallBack
  // const cb = req.query.cb;
  // cb({})
  / / res. End (` ${cb} (${JSON. Stringify ({name: "mascherano"})}) `)
  res.jsonp({name:'Little Pony'})
})
app.listen(3000);
Copy the code

Disadvantages of JSONP: Only one get request can be implemented.

Nodejs middleware proxies cross domains

Implementation Principle: The same origin policy is a standard that the browser must comply with. However, the same origin policy is not required if the server requests the same origin policy to the server. For proxy servers, you need to do the following steps:

  • Accept client requests.
  • Forwards the request to the server.
  • Get the server response data.
  • The response is forwarded to the client.

The index.html file, through a proxy server http://127.0.0.1:8080 http://localhost:3000/user request data to the target server

<! DOCTYPEhtml>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>

<body>
  <script src='/axios/dist/axios.js'></script>
  <h2>Middleware proxies cross domains</h2>
  <script>
    axios.defaults.baseURL = 'http://localhost:8080';    
    axios.get('/user')
      .then(res= > {
        console.log(res);

      })
      .catch(err= > {
        console.log(err);

      }) 
  </script>

</body>

</html>
Copy the code

Proxyserver. js proxyServer

const express = require('express');
const { createProxyMiddleware } = require('http-proxy-middleware');
const app = express();

// Proxy server operation
// Set to allow cross-domain access to the service.
app.all(The '*'.function (req, res, next) {
  res.header('Access-Control-Allow-Origin'.The '*');
  res.header('Access-Control-Allow-Headers'.'Content-Type');
  res.header('Access-Control-Allow-Methods'.The '*');
  res.header('Content-Type'.'application/json; charset=utf-8');
  next();
});

// http-proxy-middleware
// The middleware forwards each request to the http://localhost:3001 backend server
app.use('/', createProxyMiddleware({ target: 'http://localhost:3001'.changeOrigin: true }));

app.listen(8080);
Copy the code

Business server server.js

const express = require('express');
const fs = require('fs');
const app = express();
// Middleware methods
// set node_modules to the static resource directory
/ / in the future if you use the SRC attribute in the template at http://localhost:3000/node_modules
app.use(express.static('node_modules'))
app.get('/'.(req,res) = >{
  fs.readFile('./index.html'.(err,data) = >{
    if(err){
      res.statusCode = 500;
      res.end('500 Interval Serval Error! ');
    }
    res.statusCode = 200;
    res.setHeader('Content-Type'.'text/html'); res.end(data); })})// app.set('jsonp callback name', 'cb')

app.get('/user'.(req,res) = >{
  res.json({name:'Little Pony'})
})
app.listen(3001);
Copy the code

Cross domains through CORS

// Set to allow cross-domain access to the service.
app.all(The '*'.function (req, res, next) {
    /// Domain name that can be accessed across domains: Write the full port (protocol + domain name + port) if there is no port, do not add '/' at the end of the port.
    res.header('Access-Control-Allow-Origin'.The '*');
    res.header('Access-Control-Allow-Headers'.'Content-Type');
    res.header('Access-Control-Allow-Methods'.The '*');
    res.header('Content-Type'.'application/json; charset=utf-8');
    next();
});
Copy the code

Concrete implementation:

  • Respond to simple requests: the verb is get/post/head, if there is no custom request header, content-Type is one of Application/X-www-form-urlencoded,multipar/form-data or Text /plagin, by adding to The solution

     res.header('Access-Control-Allow-Origin'.The '*');
    Copy the code
  • To respond to a prefight request, you need to respond to the options request (precheck request) issued by the browser and set the response header as appropriate

    // Set to allow cross-domain access to the service.
    app.all(The '*'.function (req, res, next) {
        res.header('Access-Control-Allow-Origin'.'http://localhost:3002');
        // Allow tokens to pass
        res.header('Access-Control-Allow-Headers'.'Content-Type,X-Token');
        res.header('Access-Control-Allow-Methods'.'GET,POST,PUT');
        // Cookies are allowed
        res.header('Access-Control-Allow-Credentials'.'true');
        res.header('Content-Type'.'application/json; charset=utf-8');
        next();
    });
    Copy the code

    The front end

    Here are some examples of axios usage. Watch the video for details

    <! DOCTYPEhtml>
    <html lang="en">
    
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
      <meta http-equiv="X-UA-Compatible" content="ie=edge">
      <title>Document</title>
    </head>
    
    <body>
      <script src='/axios/dist/axios.js'></script>
      <script src="https://cdn.bootcss.com/qs/6.9.1/qs.js"></script>
      <h2>CORS cross-domain</h2>
      <script>
        axios.defaults.baseURL = 'http://127.0.0.1:3002';
        axios.defaults.headers.common['Authorization'] = 'xaxadadadadad';
        axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
    
        axios.interceptors.request.use(function (config) {
          let data = config.data;
          data = Qs.stringify(data);
          config.data = data;
          // What to do before sending the request
          return config;
        }, function (error) {
          // What to do about the request error
          return Promise.reject(error);
        });
        axios.post('/login', {
            username: 'xiaomage'.password: 123
          }, {
            // headers: {
            // 'Authorization': 'adjahdj1313131'
            // },
            // Indicates that cross-domain requests require credentials to allow cookies to be carried
            withCredentials: true
          })
          .then(res= > {
            console.log(res);
          }).catch(err= > {
            console.log(err);
    
          })
      </script>
    
    </body>
    
    </html>
    Copy the code

Use the third-party plugin CORS

npm i cors -S
Copy the code

server.js

const cors = require('cors');
// Easy to use
app.use(cors())
Copy the code

Configuration options reference link

ex:

app.use(cors({
  origin:'http://localhost:3002'.// Set the original address
  credentials:true.// Cookies are allowed
  methods: ['GET'.'POST'].// The type of requests that are allowed across domains
  allowedHeaders:'Content-Type,Authorization' // Allow the request header to carry information
}))
Copy the code

Nginx reverse proxy

The implementation principle is similar to Node middleware proxy, requiring you to build a nginx server for forwarding requests.

Nginx reverse proxy is the simplest way to cross domains. Nginx only needs to change the configuration to solve the cross-domain problem, support all browsers, support sessions, no code changes, and do not affect server performance.

Nginx configure a proxy server (domain name and domain1 the same, different port) as a jumper, reverse proxy access to domain2 interface, and can incidentally modify the cookie in the domain information, convenient for the current domain cookie writing, cross-domain login.

// Proxy serverserver {
    listen       81;
    server_name  www.domain1.com;
    location / {
        proxy_pass   http://www.domain2.com:8080;  # Reverse proxy
        proxy_cookie_domain www.domain2.com www.domain1.com; # change the domain name in cookie
        index  index.html index.htm;
        # When accessing Nignx using middleware proxy interfaces such as Webpack-dev-server, there is no browser participation, so there is no source restriction, the following cross-domain configuration can not be enabled
        add_header Access-Control-Allow-Origin http://www.domain1.com;  # If the current end is cross-domain only without cookies, the value can be *
        add_header Access-Control-Allow-Credentials true; }}Copy the code