多种跨域方式实现原理

318 阅读3分钟

1 jsonp

前端发送

 function jsonp({url,params,cb}) {
      return new Promise((resolve,reject)=>{
        let script = document.createElement('script');
        window[cb] = function (data) {
          resolve(data);
          document.body.removeChild(script);
        }
        params = {...params,cb} // wd=b&cb=show
        let arrs = [];
        for(let key in params){
          arrs.push(`${key}=${params[key]}`);
        }
        script.src = `${url}?${arrs.join('&')}`;
        document.body.appendChild(script);
      });
    }
    // 只能发送get请求 不支持post put delete
    // 不安全 xss攻击  不采用
    jsonp({
      url: 'http://localhost:3000/say',
      params:{wd:'你好'},
      cb:'show'
    }).then(data=>{
      console.log(data);
    });

node后端接收

let express = require('express');
let app = express();

app.get('/say',function (req,res) {
  let {wd,cb} = req.query;
  console.log(wd); 
  res.end(`${cb}('你好')`) 
})
app.listen(3000);

2 cors

  • 前端向域名不同的地址发送Ajax请求
  • 后端需要设置相应的请求头(内容如下)
let express = require('express');
let app = express();
let whitList = ['http://localhost:3000']
app.use(function (req,res,next) {
  let origin = req.headers.origin;
  if(whitList.includes(origin)){
    // 设置哪个源可以访问我
    res.setHeader('Access-Control-Allow-Origin', origin);
    // 允许携带哪个头访问我
    res.setHeader('Access-Control-Allow-Headers','name');
    // 允许哪个方法访问我
    res.setHeader('Access-Control-Allow-Methods','PUT');
    // 允许携带cookie
    res.setHeader('Access-Control-Allow-Credentials', true);
    // 预检的存活时间
    res.setHeader('Access-Control-Max-Age',6);
    // 允许返回的头
    res.setHeader('Access-Control-Expose-Headers', 'name');
    if(req.method === 'OPTIONS'){
      res.end(); // OPTIONS请求不做任何处理
    }
  }
  next();
});
app.put('/getData', function (req, res) {
  console.log(req.headers);
  res.setHeader('name','jw');
  res.end("你好")
})
app.get('/getData',function (req,res) {
  console.log(req.headers);
  res.end("你好")
})
app.use(express.static(__dirname));
app.listen(4000);

3 postMessage

  • a页面在端口3000下访问
  • b页面在端口4000下访问

a.html

<!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>Document</title>
</head>
<body>
  <iframe src="http://localhost:4000/b.html" frameborder="0" id="frame" onload="load()"></iframe>
  <script>
    function load() {
      let frame = document.getElementById('frame');
      frame.contentWindow.postMessage('你好','http://localhost:4000');
      window.onmessage = function (e) {
        console.log(e.data);
      }
    }
  
  </script>
</body>
</html>

b.html

<!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>Document</title>
</head>
<body>
  <h1>nihao</h1>
  <script>
    console.log(1)
    window.onmessage = function (e) {
      console.log(e.data);
      e.source.postMessage('nihao',e.origin)
    }
  </script>
</body>
</html>

4 window .name

  • a.html和b.html是同域的http://localhost:3000
  • c.html是独立的http://localhost:4000
  • a.html获取c.html的数据
  • a.html先引用c.html, c.html把值放到window .name,把a引用的地址改到b

5 hash

  • 路径后面的hash值可以用来通信(a.html和b.html是同域的,和c.html是跨域的)
  • 目的a.html想访问c.html的内容
  • a.html给c.html传一个hash值,c.html收到hash值后,c.html把hash值传递给b.html
  • b.html将结果放到a.html的hash值中

a.html

<!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>Document</title>
</head>
<body>
  <iframe src="http://localhost:4000/c.html#iloveyou"></iframe>
  <script>
    window.onhashchange = function () {
      console.log(location.hash);
    }
  </script>
</body>
</html>

b.html

<!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>Document</title>
</head>
<body>
  <script>
    window.parent.parent.location.hash = location.hash  
  </script>
</body>
</html>

c.html

<!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>Document</title>
</head>
<body>
<script>
  console.log(location.hash);
  let iframe = document.createElement('iframe');
  iframe.src = 'http://localhost:3000/b.html#nihaoa';
  document.body.appendChild(iframe);
</script>
</body>
</html>

6 document.domain

如果主域名相同,二级域名不同,想要数据通信,可以通过iframe嵌套,并且在嵌套者和被嵌套者的页面中声明

document.domain='相同的主域名'

7 websocket

前端页面

 let socket = new WebSocket('ws://localhost:3000');
    socket.onopen = function () {
      socket.send('你好');
    }
    socket.onmessage = function (e) {
      console.log(e.data);
    }

node后端

let express = require('express');
let app = express();
let WebSocket = require('ws');
let wss = new WebSocket.Server({port:3000});
wss.on('connection',function(ws) {
  ws.on('message', function (data) {
    console.log(data);
    ws.send('你好')
  });
})




8 nginx