The front cross-domain knowledge summary

Lead: In everyday development process, cross-domain is a daunting thing, but also cross-domain process learned a lot of knowledge, but also eat a lot of cross-domain loss, there has been no time to sort out this part of knowledge , now my mind Hom cross-domain knowledge and experience combined with the development process to summarize a system.

table of Contents

  • What is cross-domain
  • Cross-domain solutions

What is cross-domain

When it comes to cross-domain, you have to mention the tour's origin security policy . According to MDN said, the same origin policy restrictions and how documents and scripts and other resources from another source to interact from a document or script loaded from the same source, this is an important security mechanism to prevent a malicious program file attacks.

Homology is protocol (http \ https), domain name ( www.taobao.com) and port number ( 80, ) 8080are the same, this is called homologous, as opposed to all different sources, is the scope of cross-domain.

Here is a list a table to illustrate:

Here's a url to assume http://www.example.com/a.html, would like to request the following address, default port is 80.

No. url Whether homologous the reason
1 http://www.example.com/b.html Yes Protocol, domain names, the same port, but different file path
2 https://www.example.com/c.html no Different protocols (http \ https)
3 http://store.example.com/c.html no Subdomain different domain name (www \ store)
4 http://www.example.com:81/c.html no Different port (80/81)
5 https://shop.example.com:82/c.html no Protocol, domain names, different ports

Note : Sometimes w3c standards to ie there is not. Therefore, according to the standard ie's browser, there are two differences: First, the scope of credit, that is, two domain names highly mutual trust, free from homologous restriction; the second is two different port domain, without limitation homology.

Cross-domain solutions

As far as I know, the cross-domain in the following ways:

  • jsonp method applies only to get request
  • CROS, (Cross-Origin Resource Sharing Agreement), applicable to all kinds of requests
  • domain settings only apply to subdomains
  • post Message, suitable for parent-child communication iframe page

jsonp method

With this method, is due to the html tag srcproperty is not homologous limitation, the following packaging method jsonp a cross-domain resource request.

  • Native Method
function jsonp({url,callback}) {
  let script = document.createElement('script');
  script.src = `${url}&callback=${callback}`;
  document.head.appendChild(script);
}

A simple case:

First with node 3000 to open a port and as a server, start node server.js.

// 保存为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!');
})

The last request to return the contents.

jsonp({
  url: 'http://localhost:3000/jsonp?from=1',
  callback: 'getData',
})

function getData(res) {
  console.log(res); // {title: "hello,jsonp!"}
}
  • 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!"}
    }
  })
})

CROS

CORS (Cross -Origin Resource Sharing), cross-domain resource sharing, is a W3C standard, the standard protocol issued on the basis of http.

CORS need to visit the server and supports to address the limitations homologous's browser, making cross-domain resource request can be achieved. It has two requests, one is a simple request, another non-simple request.

  • Simple request

Satisfy the following two conditions belong to a simple request, whereas non-simple.

1) Request way GET, POST, HEAD;
2) in response to header information Accept, Accept-Language, Content-Language, Last-Event-ID, Content-Type(only application/x-www-form-urlencoded, multipart/form-data, text/plain);

There are three simple request CORS fields need to increase in the response header, in the front part are Access-Controlbeginning:

1. Access-Control-Allow-OriginThis represents a request which domains to accept, if it is an asterisk, that is, any domain name can request;
2. Access-Control-Allow-CredentialsThis indicates whether the allowed cookie, default is false, not allowed;

If set trueto send a cookie, you must specify the domain name to allow domain method; http client request must be set:

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

3. Access-Control-Expose-HeadersThis means that the server acceptable response header field, if the request sent by the client carried in Cache-Control, , Content-Language, Content-Type, Expires, Last-Modifiedas well as custom request header field.

For example: a local request get interface.

Local service is enabled with access restrictions, open server.js, enter the following: setup allows the domain name http://localhost:8089, the way to allow access request is POSTa request.


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!');
})

express frame is provided 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); //测试通过
  next();
})

If you use get access http://localhost:3000/testto this interface address, then the error will be 404.

httpReq this method in the article view.

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

cors_get
cors_get
cross2.jpg
If post visit, will return to normal content.

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

post
post

  • Non-simple request

In addition to several ways that a simple request, such PUTa request, DELETEthe request, which is to send a preflight request, then the server allows, will send real request.

There are several non-simple request fields need to pass:

1 Access-Control-Allow-Methods, a comma-separated value, for example: GET,POST,DELETE;
2 Access-Control-Allow-Headers, is the default custom field or fields, for example: X-Auth-Info;
3 Access-Control-Allow-Credentials, whether or not to carry cookie information;
4. Access-Control-Max-Age, represents a valid period of the preflight request, in seconds.

For example: The following this put request, the put request to set up a server interface to request axios herein.

// 设置返回信息
const dataUpdate = JSON.stringify({
  title: 'update success!'
})
// 设置允许
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' })
  }
}

Client requests, returns the contents.

<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();

put
put

domain settings

This method is only applicable to different subdomains when cross-domain request, may be used document.domainto set.

For example: map.domaintest.orgsubdomain to the root domain domaintest.org, the following settings may be used.

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

E.g:

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';
}

domain

domain

Look at the situation, using the Google request, this can also be successful without a request to the page content subdomain.

post Message

This post Message source can safely cross-communication between the request applies to the parent page or two different pages and sub-pages, iframe is suitable for this situation.

By the parent page postMessage('<msg>','<url>'), sub-pages to receive the message, and the message is returned to the parent page, parent page monitor messageevent receive messages.

For example: http://map.domaintest.org:8089/parent.htmlsending a message to a subpage http://map.domaintest.org:8089/son.html, subpage return message.

  • Parent page:
<!DOCTYPE html>
<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>父级页面</title>
</head>
<body>
  <button id="btn">发送消息</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('接收到的消息是:'+ data);
    })
  </script>
</body>
</html>

parent

  • Subpages:
<!DOCTYPE html>
<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>子页面</title>
</head>
<body>
  <h2>窗口</h2>
  <p>我是另外一个窗口!</p>
  <script>
    window.addEventListener('message', function (e) {  
      if (e.source != window.parent) return;
      window.parent.postMessage('我是来自子页面的消息!', '*');
    }, false)
  </script>
</body>
</html>

son

Cross-domain proxy method supplement

Sometimes the cross-domain request may be sent using the proxy manner, such as cross-domain axios agents, cross-domain NodeJS agents, cross-domain Nginx agent. The following several common cross-domain proxy settings introduced.

  • axios cross-domain agent

Create an instance of an agency:

import axios from 'axios';
var server = axios.create({
  baseURL: 'https://domain.com/api/',
  timeout: 1000,
});
  • vue cross-domain settings

In the config/index.jsset:

module.exports = {
  dev: {
    //...
    proxyTable: {
      '/api': {
          target: 'http://10.0.100.7:8081', //设置调用接口域名和端口号别忘了加http
          changeOrigin: true,
          pathRewrite:{
            "^/api":""
          }
      }
    },
  }

Interface When call:

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

According to Acting Deputy package

npm i -S http-proxy

Cross-domain settings

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

//服务端口
var PORT = 8080;
//接口前缀
var API_URL='api';
//真正的api地址
var API_DOMAIN='http://www.example.com/';

//创建一个代理服务器
var proxy = httpProxy.createProxyServer({
    target: API_DOMAIN,
});

//代理出错则返回500
proxy.on('error', function(err, req, res){
    res.writeHead(500, {
      'content-type': 'text/plain'
    });
    res.end('server is error!');
});

//建立一个本地的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';

    //判断如果是接口访问,则通过proxy转发
    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 + ".");
  • nginx proxy cross-domain

Set 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';
  }
}

Or reverse proxy

server {
  listen       80; #监听80端口
  server_name  localhost; # 当前服务的域名
  location / {
    proxy_pass http://localhost:81;
    proxy_redirect default;
  }

  location /apis { #添加访问目录为/apis的代理配置
    rewrite  ^/apis/(.*)$ /$1 break;
    proxy_pass   http://localhost:82;
  }
}

Written in the last

Cross-domain method would introduce so much, what do not understand can give me a message, my GitHub , more Welcome to my personal blog .

Guess you like

Origin www.cnblogs.com/guanqiweb/p/12454968.html