跨常见的域

248 阅读5分钟

一、jsonp

  • 缺点:只能 get,不支持post、put、delete
  • 不安全 xss
// 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);
     });
   }
   jsonp({
     url: 'http://localhost:3000/say',
     params:{wd:'我爱你'},
     cb:'show'
   }).then(data=>{
     console.log(data);
   });

二、cors

  • 后端设置
<!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>
   let xhr = new XMLHttpRequest;
   document.cookie = 'name=zfpx';
   xhr.withCredentials = true; //强制带上cookie
   xhr.open('PUT','http://localhost:4000/getData',true);
   xhr.setRequestHeader('name','zfpx');
   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('name'));
       }
     }
   }
   xhr.send();
 </script>
</body>
</html>
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);
   // 预检的存活时间 6秒内不接受请求
   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);

三、iframe

  • postMessage页面之间的互相通信
<!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>
<!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.onmessage = function (e) {
      console.log(e.data);
      e.source.postMessage('我不爱你',e.origin)
    }
  </script>
</body>
</html>
  • window.name
//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>
  a和b是同域的 http://localhost:3000
  c是独立的  http://localhost:4000
  a获取c的数据
  a先引用c c把值放到window.name,把a引用的地址改到b
  <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>
</html>
//b.html 空
//c.html =
<body>
  <script>
    window.name = '我不爱你'  
  </script>
</body>
  • location.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#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#idontloveyou';
 document.body.appendChild(iframe);
</script>
</body>

</html>
  • domain
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>
 <!-- 域名 一级域名二级域名 -->
 <!-- www.baidu.com -->
 <!-- viode.baidu.com -->
 <!-- a是通过 http://a.zf1.cn:3000/a.html -->
 helloa
 <iframe src="http://b.zf1.cn:3000/b.html" frameborder="0" onload="load()" id="frame"></iframe>
 <script>
   document.domain = 'zf1.cn'
   function load() {
     console.log(frame.contentWindow.a);
   }
 </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>
  hellob
  <script>
     document.domain = 'zf1.cn'
    var a = 100;
  </script>
</body>
</html>

四、websocket

  • 高级api ,不兼容,一般用(socket.io) 速度快,平等的双方的通信
  • 没有跨域限制,需要服务端配合
  • 发给服务器,服务器发送到另一个页面。服务端安装ws,
// 前端
<!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('我爱你');
    }
    socket.onmessage = function (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('我不爱你')
  });
})

五、nginx跨域

*新增加个json文件,写mock数据

  • 修改nginx 的配置文件conf, 新增内容为: loactin ~..json{ root json; add_header 'Access-Control-Allow-origin' ''; // 解决跨域 }

  • 重启下nginx就可以

  • 在默认文件目录下添加json文件的路由,就可以获取json文件的内容(此为不跨域)。

  • 如果其它地址请求会出现跨域问题。解决办法为:添加 add_header 'Access-Control-Allow-origin' '*';