Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

跨域

同源策略

  • 是⼀种浏览器的安全协议,限制了从同一个源加载的文档或脚本如何与另一个源的资源进行交互

  • 同源指的是:协议、域名、端口 都必须一致

  • 举例说明

    • ⽐如⼀个⿊客程序,如果没有同源限制,那么他利⽤ Iframe 就可以把真正的银⾏登录⻚⾯嵌到他的⻚⾯上,当你使⽤真实的⽤户名,密码登录时,他的⻚⾯就可以通过 Javascript 读取到你的表单中 input 中的内容,这样⽤户名,密码就轻松到⼿了
  • 浏览器的同源策略会造成跨域问题

解决跨域问题的几种方式

  • CORS

    • 后端返回的请求头加上Access-Control-Allow-Origin字段
      • 设置成*,任何请求都可以跨域
      • 或者设置某个域名,只要请求Header的Origin是这个域名,就能跨域
    • 两种情况
      • 对于简单请求,会直接返回
      • 对于非简单请求,需要先用OPTIONS进行预检
    • 可借助nginx代理实现
      location / {
          add_header Access-Control-Allow-Origin *;
      }
      
    • 也可借助node中间件实现
      const cors = require("@koa/cors");
      app.use(
        cors({
          origin: "http://www.domain2.com",
        }),
      );
      
    • 也可以在前端项目webpack的devServer中实现
      module.exports = {
          entry: {},
          module: {},
          ...
          devServer: {
              historyApiFallback: true,
              proxy: [{
                  context: '/login',
                  target: 'http://www.domain2.com:8080',  // 代理跨域目标接口
                  changeOrigin: true,
                  secure: false,  // 当代理某些https服务报错时用
                  cookieDomainRewrite: 'www.domain1.com'  // 可以为false,表示不修改
              }],
              noInfo: true
          }
      }
      
  • JSONP

    • 利用<script>标签没有跨域限制,通过<script>标签src属性,发送带有callback参数的GET请求
    • 缺点
      • 具有局限性,仅支持get方法
      • 不安全,可能会遭受XSS攻击
    • 原生实现例子
      <script>
          var script = document.createElement('script');
          script.type = 'text/javascript';
          // 传参一个回调函数名给后端,方便后端返回时执行这个在前端定义的回调函数
          script.src = 'http://www.domain2.com:8080/login?user=admin&callback=handleCallback';
          document.head.appendChild(script);
          // 回调执行函数
          function handleCallback(res) {
              alert(JSON.stringify(res));
          }
      </script>
      
    • axios实现例子
      axios
        .jsonp("http://www.domain2.com:8080/login", {
          params: {},
          jsonp: "handleCallback",
        })
        .then((res) => {
          console.log(res);
        });
      
  • postMessage

    • 是 HTML5 XMLHttpRequest Level 2 新增的API
      • 用于多个窗口间的跨域消息传递
    • 例子
      • a.html(窗口1)
        <iframe id="iframe" src="http://www.domain2.com/b.html" style="display:none;"></iframe>
        <script>
            var iframe = document.getElementById('iframe');
            iframe.onload = function() {
                var data = {
                    name: 'aym'
                };
                // 向domain2传送跨域数据
                iframe.contentWindow.postMessage(JSON.stringify(data), 'http://www.domain2.com');
            };
            // 接受domain2返回数据
            window.addEventListener('message', function(e) {
                alert('data from domain2 ---> ' + e.data);
            }, false);
        </script>
        
      • a.html(窗口2)
        <script>
            // 接收domain1的数据
            window.addEventListener('message', function(e) {
                alert('data from domain1 ---> ' + e.data);
                var data = JSON.parse(e.data);
                if (data) {
                    data.number = 16;
                    // 处理后再发回domain1
                    window.parent.postMessage(JSON.stringify(data), 'http://www.domain1.com');
                }
            }, false);
        </script>
        
  • 在js标签中设置crossorigin="anonymous"???