多种跨域方式

了解同源

首先先了解一下,同源是指 protocol://hostName:port 三者相同,即便两个不同的域名指向同一个ip,也为非同源。

同源策略下,非同源之间有以下限制:

  1. cookie, localStorage, indexDB 无法读取

  2. Dom和JS对象无法获得

  3. ajax 请求不能发送

JSONP

function jsonp ({url, params, callback}) {
  return new Promise ((resolve, reject) => {
    let script = document.createElement('script');
    window[callback] = function(data) {
      resolve(data);
      document.body.removeChild(script);
    }
    params = {...params, callback};
    let arr = [];
    for (const key in params) {
      arr.push(`${key}=${params[key]}`);
    }
    script.src = `${url}?${arr.join('&')}`;
    document.body.appendChild(script);
  });
}

jsonp({
  url: 'http://localhost:8989/blog/',
  params: {
    name: 'kk'
  },
  callback: 'show'
}).then(data => {
  console.log(data);
})

CORS

1. 设置withCredentials, 请求的时候带上cookie

let xhr = new XMLHttpRequest();
document.cookie = 'name=kk'; // cookie不能跨域
xhr.withCredentials = true; // 前端设置是否带cookie
xhr.open('PUT', 'http://localhost:3000/getData', true);
xhr.setRequestHeader('name', 'kk');
xhr.onreadystatechange = function() {
  if (xhr.readyState === 4) {
    if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
      console.log(xhr.response);
      console.log(xhr.getResponseHeader);
    }
  }
}
xhr.send();

2. 服务端做处理

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', 'kkk1111')
  res.end('我不爱你')
})
app.get('/getData', function(req, res) {
  console.log(req.headers)
  res.end('我不爱你')
})
app.use(express.static(__dirname))
app.listen(4000)

nginx

配置转发

postMessage

// a.html port: 3000
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <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('what u name?', 'http://localhost:4000');
      window.onmessage = function(e) {
        console.log(e.data);
      }
    }
  </script>
</body>
</html>
// b.html port: 4000
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>b.html</title>
</head>
<body>
  <script>
    window.onmessage = function (e) {
      console.log(e.data);
      e.source.postMessage('kk', e.origin)
    }
  </script>
</body>
</html>
img

name

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

// a.html
<body>
  <iframe src="http://localhost:4000/c.html" frameborder="0" onload="load()" id="iframe"></iframe>
  <script>
    let first = true
    function load() {
      if(first){
        let iframe = document.getElementById('iframe');
        iframe.src = 'http://localhost:3000/b.html';
        first = false;
      }else{
        console.log(iframe.contentWindow.name);
      }
    }
  </script>
</body>

b.html 里面可以什么都不写

// c.html
<script>
  window.name = 'kk';
</script>

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>
  <!-- 路径后面的hash值可以用来通信  -->
  <!-- 目的a想访问c -->
  <!-- a给c传一个hash值 c收到hash值后  c把hash值传递给b b将结果放到a的hash值中-->
  <iframe src="http://localhost:4000/c.html#whatuname?"></iframe>
  <script>
    window.onhashchange = function () {
      console.log(location.hash);
    }
  </script>
</body>
</html>
// b.html
<script>
  window.parent.parent.location.hash = location.hash  
</script>
// c.html
<script>
  console.log(location.hash);
  let iframe = document.createElement('iframe');
  iframe.src = 'http://localhost:3000/b.html#kk';
  document.body.appendChild(iframe);
</script>

domain

该方式只适用于二级域名相同的情况下

// a.html
<body>
  <h1>Hi, there is A Page</h1>

  <iframe
    id="iframe"
    src="http://test.com:2333/b.html"
    frameborder="0"
    onload="load()"
  ></iframe>

  <script>
    document.domain = "test.com";
    function load() {
      let iframe = document.getElementById('iframe');
      console.log(iframe.contentWindow.data); // This is b html content.
    }
  </script>
// b.html
<body>
  <h1>Hi, there is B Page</h1>

  <script>
    document.domain = 'test.com';
    var data = "This is b html content.";
  </script>
</body>

websocket

<!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>
    // 高级api 不兼容 socket.io(一般使用它)
    let socket = new WebSocket('ws://localhost:3000');
    socket.onopen = function () {
      socket.send('what u name?');
    }
    socket.onmessage = function (e) {
      console.log(e)
      console.log(e.data);
    }
  </script>
</body>
</html>
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('kk')
  });
})

// app.listen(3000);

http-proxy-middelware

Last Updated:
Contributors: kk