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.