Guide language: in daily during the development process, cross domain is a headache thing, also learned many knowledge in the process of cross domain, also ate a lot of cross-domain kui, there has been no time to sort out this part of the knowledge, in my mind now encountered in the process of cross domain knowledge, and combining with the development of a systematic summary.

directory

  • What is cross-domain
  • Cross-domain solutions

What is cross-domain

Speaking of cross-domain, we have to mention the same origin security policy of the tourist. According to MDN, the same origin policy restricts how documents or scripts loaded from the same source can interact with resources such as documents and scripts from another source, which is an important security mechanism against malicious file programs.

The same protocol (HTTP \ HTTPS), domain name (www.taobao.com) and port number (80,8080) are all the same, which is called the same, and the opposite is different source, is the scope of cross-domain.

Here’s a table to illustrate:

Assuming that there is a url to http://www.example.com/a.html, would like to request the following address, the default port is 80.

The serial number url Whether the same why
1 http://www.example.com/b.html is The protocol, domain name, and port are the same, but the file path is different
2 https://www.example.com/c.html no Different protocols (HTTP \ HTTPS)
3 http://store.example.com/c.html no Different subdomain names (WWW \store)
4 http://www.example.com:81/c.html no Different ports (80/81)
5 https://shop.example.com:82/c.html no Protocol, domain name, port are different

Note: Sometimes w3c standards don’t work in IE. So according to ie visitor standards, there are two differences: one is the scope of credit, that is, two domain names with high mutual trust, not subject to the same origin restrictions; Second, two domain names with different ports are not subject to the same origin restriction.

Cross-domain solutions

As far as I know, cross-domain has the following methods:

  • Jsonp method, only for GET requests
  • CROS, (Cross-domain resource sharing Protocol), is suitable for various requests
  • Domain Settings, which only apply to subdomains
  • Post Message, suitable for parent-child web iframe communication

The json approach

In this way, since the SRC attribute of the HTML tag is not subject to the same origin restriction, we will encapsulate a JSONP method to make cross-domain resource requests.

  • A native method
function jsonp({url,callback}) {
  let script = document.createElement('script');
  script.src = `${url}&callback=${callback}`;
  document.head.appendChild(script);
}
Copy the code

A simple case study:

Start nodeServer.js with port 3000 as the server.

// Save as server.js
const http = require('http');
const url = require('url');
const queryString = require('querystring');
const data = JSON.stringify({
  title: 'hello,jsonp! '
})

const server = http.createServer((request, response) = > {
  let addr = url.parse(request.url);
  if (addr.pathname == '/jsonp') {
    let cb = queryString.parse(addr.query).callback;
    response.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' })
    response.write(cb + '('+ data +') ');
  } else {
    response.writeHead(403, { 'Content-Type': 'text/plain; charset=utf-8' })
    response.write('403');
  }
  response.end();
})

server.listen(3000, () = > {console.log('Server is running on port 3000! ');
})
Copy the code

Finally, the request returns the content.

jsonp({
  url: 'http://localhost:3000/jsonp? from=1'.callback: 'getData',})function getData(res) {
  console.log(res); // {title: "hello,jsonp!" }
}
Copy the code
  • Jquery method
<script src="https://unpkg.com/[email protected]/dist/jquery.js"></script>
$(function () {  
  $.ajax({
    url: 'http://localhost:3000/jsonp? from=1'.type: 'get'.dataType: 'jsonp'.success: function(res) {
      console.log(res); // {title: "hello,jsonp!" }}})})Copy the code

CROS

Cross-origin Resource Sharing (CORS) is a W3C standard, published on the basis of HTTP standard protocol.

CORS needs to be supported by both the browser and the server, which solves the homology limitation of the browser and enables cross-domain resource requests to be realized. It has two types of requests, one simple and the other non-simple.

  • A simple request

If the following two conditions are met, it is a simple request, and vice versa.

1) Request mode is GET, POST, HEAD; 2) The response header information is Accept, accept-language, Content-language, last-event-ID, Content-Type(only application/ X-www-form-urlencoded, multiPAR) T/form – the data, the text/plain);

Simple requests have three CORS fields that need to be added to the response header, all beginning with access-Control:

Access-control-allow-origin specifies which domain name requests are accepted. If the name is *, any domain name can be requested. Access-control-allow-credentials: indicates whether cookies are allowed. The default value is false and they are not allowed.

If set to true, to send cookies, the permission field must specify the domain name method; Client HTTP requests must be set to:

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
Copy the code

3. Access-control-expose-headers, which indicates the response Headers accepted by the server, If a client sends a request with cache-Control, Content-Language, Content-Type, Expires, last-Modified, and custom request header fields.

For example, requesting a local GET interface.

Enable access restriction on the local server, open server.js, and enter the following content: Set the allowed domain name to http://localhost:8089, and set the allowed access request mode to POST.


const http = require('http');
const url = require('url');
const queryString = require('querystring');
const data = JSON.stringify({
  title: 'hello,jsonp! '
})
const dataCors = JSON.stringify({
  title: 'hello,cors! '
})

const server = http.createServer((request, response) = > {
  let addr = url.parse(request.url);
  response.setHeader("Access-Control-Allow-Origin".'http://localhost:8089');
  response.setHeader("Access-Control-Allow-Headers"."Content-Type");
  response.setHeader("Access-Control-Allow-Methods"."POST");
  response.setHeader("Content-Type"."application/json; charset=utf-8");
  if (addr.pathname == '/jsonp') {
    let cb = queryString.parse(addr.query).callback;
    response.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' })
    response.write(cb + '('+ data +') ');
  } else if (addr.pathname == '/test') {if (request.method == 'POST') {
      response.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' })
      response.write(dataCors);
    } else {
      response.writeHead(404, { 'Content-Type': 'text/plain; charset=utf-8'}}})else {
    response.writeHead(403, { 'Content-Type': 'text/plain; charset=utf-8' })
    response.write('403');
  }
  response.end();
})

server.listen(3000, () = > {console.log('Server is running on port 3000! ');
})
Copy the code

The Express framework Settings are as follows:

app.all("*".function(req, res, next) {
  res.header("Access-Control-Allow-Origin"."*");
  res.header("Access-control-Allow-Headers"."X-Auth");
  res.header("Access-Control-Allow-Methods"."GET,POST,DELETE,PUT,OPTIONS,HEAD,FETCH");
  res.header("Access-control-max-age".60*60*24); // The test passes
  next();
})
Copy the code

Visit http://localhost:3000/test if you use the get the interface address, that would be an error 404.

HttpReq This method is viewed in this article.

async function getReqData() {  
  let data = await httpReq({
    type: 'get'.url: 'http://localhost:3000/test'.data: null,})console.log(data);
}
getReqData();
Copy the code

If it is a POST access, normal content is returned.

async function getReqData() {  
  let data = await httpReq({
    type: 'post'.url: 'http://localhost:3000/test'.data: null,})console.log(data);
}
getReqData();
Copy the code

  • Non-simple request

In addition to several simple request methods, such as PUT request, DELETE request, this is to send a pre-check request, and then the server allows, will send the real request.

Non-simple requests have the following fields to pass:

Access-control-allow-methods, where values are separated by commas, such as GET,POST, and DELETE. 2. Access-control-allow-headers is the default field or user-defined field, for example, X-auth-info. 3. Access-control-allow-credentials: Specifies whether cookie information is enabled. 4. Access-control-max-age: indicates the validity period of the precheck request, in seconds.

For example, in the following PUT request, the server sets up a PUT request interface and uses AXIos to request it.

// Set the return information
const dataUpdate = JSON.stringify({
  title: 'update success! '
})
// Set permission
response.setHeader("Access-Control-Allow-Methods"."POST,PUT");
response.setHeader("Access-Control-Allow-Credentials".false);
response.setHeader("Access-Control-Max-Age".60*60*24);
if (addr.pathname == '/update') {if (request.method == 'PUT') {
    response.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' })
    response.write(dataUpdate);
  } else {
    response.writeHead(404, { 'Content-Type': 'text/plain; charset=utf-8'}}})Copy the code

Client requests, returns content.

<script src="https://cdn.bootcss.com/axios/0.19.0/axios.min.js"></script>
async function saveInfo () {
  let data = await axios.put('http://localhost:3000/update', {
    title: 'far'.body: 'bar'.userId: 121,})console.log(data);
}
saveInfo();
Copy the code

Domain set

This method only works for cross-domain requests at different times in the subdomain and can be set using document.domain.

For example, map.domaintest.org indicates the root domain name domaintest.org. You can use the following Settings.

if (document.domain ! ='domaintest.org') {
  document.domain = 'domaintest.org';
}
Copy the code

Such as:

async function saveInfo () {
  let data = await httpReq({
    type: 'get'.url: 'http://map.domaintest.org:8089/ky.html'.data: null,})console.log(data);
}
saveInfo();
if (document.domain ! ='domaintest.org') {
  document.domain = 'domaintest.org';
}
Copy the code

Depending on the case, using Google request, you can also successfully request the page content of the subdomain without this paragraph.

post Message

This post Message can safely communicate across sources and is suitable for requests between parent and child pages or between two different pages, such as iframe.

The parent page receives the message via postMessage(‘< MSG >’,'< URL >’), the child page receives the message and returns the message to the parent page, which listens for the Message event to receive the message.

For example: http://map.domaintest.org:8089/parent.html to send message to child pages http://map.domaintest.org:8089/son.html, child pages returned message.

  • Of the parent page:

      
<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>The parent page</title>
</head>
<body>
  <button id="btn">Send a message</button>
  <iframe id="child" src="http://map.domaintest.org:8089/son.html" width="100%" height="300"></iframe>
  <script>
    let sendBtn = document.querySelector('#btn');
    sendBtn.addEventListener('click', sendMsg, false);
    function sendMsg () {  
      window.frames[0].postMessage('getMsg'.'http://map.domaintest.org:8089/son.html');
    }
    window.addEventListener('message'.function (e) {
      let data = e.data;
      console.log('The message received is:'+ data);
    })
  </script>
</body>
</html>
Copy the code

  • Of a child page:

      
<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>Child pages</title>
</head>
<body>
  <h2>window</h2>
  <p>I'm another window!</p>
  <script>
    window.addEventListener('message'.function (e) {  
      if(e.source ! =window.parent) return;
      window.parent.postMessage('I am a message from a sub-page! '.The '*');
    }, false)
  </script>
</body>
</html>
Copy the code

Cross-domain proxy method supplement

Sometimes you can use proxies to send cross-domain requests, such as axios cross-domain proxy, NodeJS cross-domain proxy, and nginX cross-domain proxy. The following describes several common ways to set up a cross-domain proxy.

  • Axios’ cross-domain proxy

Create instance create proxy:

import axios from 'axios';
var server = axios.create({
  baseURL: 'https://domain.com/api/'.timeout: 1000});Copy the code
  • Cross-domain Settings in VUE

In config/index.js:

module.exports = {
  dev: {
    / /...
    proxyTable: {
      '/api': {
          target: 'http://10.0.100.7:8081'.// Set the calling interface domain name and port number and don't forget to add HTTP
          changeOrigin: true.pathRewrite: {"^/api":""}}}},Copy the code

Interface call:

this.axios.get('/api/user', {params: {
        userId:'1'
    }
}).then(function (res) {
    console.log(res);
}).catch(function (err) {
    console.log(err);
})
Copy the code
  • Nodejs cross-domain proxy

According to the proxy proxy package

npm i -S http-proxy
Copy the code

Set the cross-domain

var http = require('http');
var url=require('url');
var path=require('path');
var httpProxy = require('http-proxy');

// Service port
var PORT = 8080;
// The interface prefix
var API_URL='api';
// The real API address
var API_DOMAIN='http://www.example.com/';

// Create a proxy server
var proxy = httpProxy.createProxyServer({
    target: API_DOMAIN,
});

// Return 500 if the agent fails
proxy.on('error'.function(err, req, res){
    res.writeHead(500, {
      'content-type': 'text/plain'
    });
    res.end('server is error! ');
});

// Create a local server
var server = http.createServer(function (request, response) {
    var pathname = url.parse(request.url).pathname;
    var realPath = path.join(". /", pathname);
    var ext = path.extname(realPath);
    ext = ext ? ext.slice(1) : 'unknown';

    // If the interface is accessed, the proxy is used for forwarding
    console.log(pathname);
    console.log(API_URL);
    if(pathname.indexOf(API_URL) > 0) {console.log(request.url.substring(4,request.url.length));
        request.url=request.url.substring(4,request.url.length)
        proxy.web(request, response);
        return; }}); server.listen(PORT);console.log("Server runing at port: " + PORT + ".");
Copy the code
  • Nginx cross-domain proxy

Set the cors

location / { if ($request_method = 'OPTIONS') { add_header 'Access-Control-Allow-Origin' '*'; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type'; add_header 'Access-Control-Max-Age' 64800; add_header 'Content-Type' 'text/plain charset=UTF-8'; add_header 'Content-Length' 0; return 204; } if ($request_method = 'POST') { add_header 'Access-Control-Allow-Origin' '*'; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type'; } if ($request_method = 'GET') { add_header 'Access-Control-Allow-Origin' '*'; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type'; }}Copy the code

Or reverse proxy

server { listen 80; Server_name localhost; Location / {proxy_pass http://localhost:81; proxy_redirect default; Rewrite ^/apis/(.*)$/$1 break; rewrite ^/apis/(.*)$/$1 break; proxy_pass http://localhost:82; }}Copy the code

Write in the last

So much for the cross-domain approach. If you don’t understand anything, you can leave a message to me on Github and get more. Welcome to visit my personal blog.