多種跨域方式實現原理

碧螺春發表於2018-09-29

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

相關文章