The same-origin policy

Browsers have the same origin policy. If they have different protocol domain names and ports, they cannot access resources from each other

Achieve cross-domain

  • jsonp
  • cors
  • postMessage
  • Window.name
  • http-proxy
  • Document.domain

JSONP

  1. Declare a function locally
function show(data){
  console.log(data)
}
Copy the code
  1. The latter section returns the execution of the function
<script src="https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=lol&cb=show"></script>// cb is the name of the executive function that returns the thicknessCopy the code
/ / the back-end returns show ({p: false q: "lol" s: (10) [" lol website ", "lol mobile game", "turn lol area", what do you mean "lol", "lol half price", "spring" lol ", "turn lol area system"]})Copy the code

Encapsulate a generic JONSP function

/ / use
jsonp({
  url:'xxx'.params: {wd:'xxx'},
  cb:'xx'
}).then(res= >console.log(data))
Copy the code
let jsonp = ({url,params,cb}) = >{
 return new Promise((resolve,reject) = >{
    1. Create a script tag
   let script = document.createElement('script')
   //3. Mount cb to the global system. The back-end system returns CB data
   window[cb]=function(data){
     resolve(data)
   //4. Remember to add to script delete
     script.remove()
   }
   // convert params and cb to wd=xxx&cb= XXXparams = {... params,cb}let arr = []
   for(let key in params){
     arr.push(`${key}=${params[key]}`)
   }
   script.src=url+'? '+arr.join('&')
   document.body.appendChild(script)
 })
}
Copy the code

The disadvantage of the json

  1. Only GET requests can be sent, but post, PUT, and DELETE are not supported
  2. Unsafe, reference links to websites that may cause harm if they return an attack code, XSS attacks, not supported

Node provides JSONP functionality under emulation

let express = require('express')
let app = new express()
app.get('/say'.function(req,res){
	let {wd,cb}=req.query
	res.end(`${cb}(' returned data ') ')
})
app.listen(3000.function(){console.log('start')})
Copy the code

cors

This is a back-end solution that can be simulated using Node

Start two servers, one 3000 port and one 4000 port

Port 3000 starts a web page to access resources of port 4000

const express = require('express');
let app = express();
// Provide access to the resources in this directory as static resources
app.use(express.static(__dirname));
app.listen(3000.function () {
	console.log('3000 start');
});
Copy the code
// index.html
<script>
  let xhr = new XMLHttpRequest();
  xhr.open('get'.'http://localhost:4000/say');
  xhr.onreadystatechange = function () {
    if(xhr.readyState === 4 && 300 >= xhr.status&&xhr.status >= 200) {
      console.log(xhr.response); }}; xhr.send();</script>
Copy the code

Browser input: localhost: 3000 / index. HTML, warns cross-domain problem

And the port: 4000 service receives a request to port 3000, but the returned content is blocked by the browser

Access-control-allow-origin does not Allow http://localhost:3000 to Access resources, yes

Set the allowed domain name

// Set a whitelist of allowed domain names
let whiteList = ['http://localhost:3000'];
app.use(function (req, res, next) {
  // Get the origin of the request
    let origin = req.headers.origin;
    if (whiteList.includes(origin)) {
    // If it is in the whitelist, access is allowed
        res.setHeader('Access-Control-Allow-Origin', origin);
    }
    next();
});
Copy the code

Sets the request mode to allow access

But this method only allows simple requests like GET, POST,head, or put

xhr.open('put'.'http://localhost:3000/say')
Copy the code
app.put('/say'.function(req,res){
  res.end('post request')})Copy the code

The browser has reported an error and we need the backend Settings to allow PUT requests

app.use(function(req,res){
    res.setHeader('Access-Control-Allow-Methods'.'PUT')// Remember uppercase
})
Copy the code

Sets the request headers that need to be allowed access

What if we add some information to the request header,

xhr.setRequestHeader('name'.'huzhiwu')
Copy the code

The browser warns that the backend is required to allow that request header

But port 4000 can accept this request header

Sets the allowed headers

res.setHeaders('Access-Control-Allow-Headers'.'name')
Copy the code

Set the Max – age

We print the method for each request in port 4000’s service

app.use(function(req,res){
	console.log(req.method)
})
Copy the code

When you refresh your browser, you’ll notice. Port 4000 prints two methods

Options means that when the browser discovers cross-domain, it will send a pre-check request to the server. This method returns methods that allow access. If the request method is not in methods, an error will be reported

So if we’re sending one request at a time, and we’re actually sending two requests, it’s a little bit more expensive, so if we don’t change our method very often, we can make it

It is enough for the browser to pre-check once at a time

req.setHeader('Access-Control-Max-Age'.5)/ / unit of seconds
Copy the code

Allows cookies to be carried across domains

let xhr = new XMLHttpRequest();
xhr.open('put'.'http://localhost:4000/say');
document.cookie='name=huzhiwu'
xhr.onreadystatechange = function () {
  if (xhr.readyState === 4 && 300 >= xhr.status && xhr.status >= 200) {
  	console.log(xhr.response); }}; xhr.send();Copy the code
// Server with port 4000
app.use(function(req,res){
  console.log(req.headers)
})
Copy the code

We found no cookies we were carrying

Add in the Ajax request

xhr.withCredentials = true;
Copy the code

Browser error again

Allow cookies to be carried across domains in Node

res.serHeader('Access-Control-Allow-Credentials')
Copy the code

Allows the browser to get the HEADERS returned by the server

app.put('/say'.function(req,res){
  res.setHeader('name'.'huzhiwu')
  res.end('put')})Copy the code
let xhr = new XMLHttpRequest();
xhr.open('put'.'http://localhost:4000/say');
xhr.onreadystatechange = function () {
	if (xhr.readyState === 4 && 300 >= xhr.status && xhr.status >= 200) {
		console.log(xhr.getResponseHeader('name')); }}; xhr.send();Copy the code

The browser reported an error again

The browser doesn’t think the request header the server returns to you is safe and won’t give it to you

Set in Node

res.setHeader('Access-Control-Expose-Headers'.'name')
Copy the code

summary

// Allow which source can access me
res.setHeader('Access-Control-Allow-Origin',origin)
// Allow that method to access me
res.setHeader('Access-Control-Allow-Methods'.'PUT')
// Precheck the survival time
res.setHeader('Access-Control-Max-Age'.5)/ / unit of seconds
// Allow headers to be carried
res.setHeader('Access-Control-Allow-Headers'.'name')
// Allow the browser to get the headers returned by the server
res.setHeader('Access-Control-Expose-Headers'.'name')
Copy the code

PostMessage cross-domain

Pages communicate with pages nested in iframe

Enable services A and B respectively on ports 3000 and 4000

//a.js b.js
const express = require('express');
const app = express();
app.use(express.static(__dirname));
app.listen(4000/3000.function () {
	console.log('4000/3000 start');
});
Copy the code

Put page A on port 3000 and page B on port 4000

Reference page A in page B

<body>
  <iframe src='http://localhost:3000/a.html' id='aIframe' onload='load()'>
  </iframe>
  <script>
  	function load(){
  	    let frame = document.getElementById('aIframe')
  	    // Send a message to the window of the page nested in the iframe
  	    // The second argument is origin
  	    frame.contentWindow.postMessage('Hello, THIS is PAGE B'.'http://localhost:3000/a.html')}// Page B listens for information from page A
    window.onmessage=function(e){
      console.log(e.data)
    }
  </script>
</body>
Copy the code

Listen for information on page B on page A

window.onmessage=function(e){
  console.log(e.data)
  // After receiving the message, send the message to page B,
  e.source.postMessage('Hello, this is page A', rigin)}Copy the code

The browser open http://localhost:4000/b.html

summary

Send a message

window.postMessage('information'The orign)Copy the code

Receive information

window.onmessage=function(e){
  console.log(e.data)
}
Copy the code

Window. The name across domains

Window.name is an empty string by default. We can store information in name and access it across domains

  1. A and B are symtopichttp://localhost:3000
  2. C is for another domainhttp://localhost:4000
  3. Page A uses iframe to reference C and iframe to reference B.
  4. The window.name of page C can be obtained from page A

Start two servers with ports 3000 and 4000 respectively

C page

<script>
	window.name='I'm c page'  
</sctript>
Copy the code

A page

<body>
  <iframe src='http://localhost:4000/c.html' id='frame' onload='load()'>
  </iframe>
  <script>
    let first=true
    let frame = document.getElementById('frame')
    function load(){
  	// Immediately after the first load, transfer the frame SRC to the same source
  	if(first){
  	    frame.src='http://localhost:3000/b.html'
  	    first=false;
  	}else{
  	    // Under the same name, you can access name
  	    console.log(frame.contentWindow.name)
  	}
        
    }
  </script>
</body>
Copy the code

http-proxy

Proxies can be used when network requests cross domains.

Server access servers have no cross-domain problems. So, what we do is we use the proxy browser in the middle to send requests to the target browser.

  1. Enable the services for ports 3000 and 4000 respectively
  2. A The page is stored in port 3000
  3. Page A sends the request, and the server at port 3000 forwards the request to port 4000
a.js
const express = require('express');
const { createProxyMiddleware } = require('http-proxy-middleware');
// Forward the request to another server
const apiProxy = createProxyMiddleware('/say', {
	target: 'http://localhost:4000'});const app = express();
app.use(express.static(__dirname));
app.use(apiProxy);
app.listen(3000.function () {
	console.log('3000 start');
});
Copy the code
b.js
const express = require('express');
const app = express();
app.use(express.static(__dirname));
app.get('/say'.function (req, res) {
	res.end('THIS is information from server B');
});
app.listen(4000.function () {
	console.log('4000 start');
});
Copy the code
<script>
    let xhr = new XMLHttpRequest();
    xhr.open('get'.'http://localhost:3000/say');
    xhr.onreadystatechange = function () {
        if (xhr.readyState === 4 && 300 >= xhr.status && xhr.status >= 200) {
            console.log(xhr.response); }}; xhr.send();</script>
Copy the code

The HTTP proxy – middleware see https://github.com/chimurai/http-proxy-middleware for more parameters

Document. The domain across domains

For example, www.video.baidu.com and www.map.baidu.com are two secondary domain names,

// www.map.baidu.com
<body>
  <script>
  	window.name='huzhiwu'
  </script>
</body>
// www.video.baidu.com
<body>
  <iframe src='www.map.baidu.com' id='frame' onload='load'>
  </iframe>
  <script>
  function load(){
      let frame = document.getElementById('frame')
      console.log(frame.contentWindow.name)// Cross-domain access failed
  }
  </script>
</body>
Copy the code

Because there is no cross-domain access,

But as long as the two secondary domain name add document.domain=’baidu.com’ can access each other

code

Github.com/huzhiwu1/Sa…

conclusion

Author: Hu Zhiwu

Time: 2020/05/06

If you like it, please give it a thumbs up. If you have any mistakes, please correct them