前端跨域问题总结


1. 同源策略

所谓同源是指,域名协议端口相同。浏览器在非同源时限制了以下三种行为:

  • CookieLocalStorageIndexDB 的读取
  • DOM 的获取
  • AJAX 请求

2. 跨域问题

  • 跨域只存在于浏览器端,不存在于 安卓iosNode.jspythonjava等其它环境
  • 跨域请求能发出去,服务端能收到请求并正常返回结果,只是结果被浏览器拦截了

3. Cookie、LocalStorage及DOM跨域访问

  • 设置document.domain
    这种方法适用于两个网页一级域名相同,只是次级域名不同的情况。比如http://a.test.com/a.htmlhttp://b.test.com/b.html
    只要在两个网页中设置相同的document.domain,两个网页就可以共享 CookieLocalStorage以及获取DOM
    document.domain = 'test.com';
  • window.postMessage()
    window.postMessage()是一个跨文档通信API,允许两个窗口进行通信而不受同源策略的限制。
    // 发送消息
    targetWindow.postMessage(message, targetOrigin)
    
    // 接收消息
    window.addEventListener("message", (event) => {
        // 消息来源域名过滤
        if (event.origin !== "http://example.org:8080") return;
    
        // ...
    }, false);

4. AJAX 请求跨域

  • JSONP
    借助于 <script> 标签的 src 属性,只能发 GET 请求

    <!-- 向服务器test.com发出请求,该请求的查询字符串有一个callback参数,用来指定回调函数 -->
    <script src="http://www.test.com/getData?callback=getData"></script>
    
    <!-- 处理服务器返回回调函数的数据 -->
    <script type="text/javascript">
        // 服务器返回的数据会放到回调函数里面
        function getData(res) {
            // 处理获得的数据
            console.log(res.data)
        }
    </script>
  • CORS
    CORS (Cross-Origin Resource Sharing)是跨域资源共享的缩写。在服务端响应头中添加Access-Control-相关字段,来允许跨域请求。

    // *表示允许任意源的访问,也可以指定特定的源
    Access-Control-Allow-Origin:*  
    
    // 表示跨域访问时带上cookie,需同时在ajax请求中设置`withCredentials: true`,
    Access-Control-Allow-Credentials: true
    
    // 允许的方法,多个方法以逗号分隔
    Access-Control-Allow-Methods: GET, POST, PUT
    
    // 允许的头部,多个头部以逗号分隔
    Access-Control-Allow-Headers:Content-Type
    
    // 允许浏览器在指定时间内,无需再发送预检请求进行协商,单位为秒
    Access-Control-Max-Age: 1728000

    Node.js 项目中可以直接使用cors模块来快速实现。

    const express = require('express')
    
    // 引入cors模块,需要单独安装
    const cors = require('cors')
    
    const app = express()
    app.use(cors())
  • WebSocket
    WebSocket 是HTML5的一个持久化的协议,它实现了浏览器与服务器的全双工通信。WebSocketHTTP 都是应用层协议,都基于 TCP 协议。但是 WebSocket 是一种双向通信协议,在建立连接之后,WebSocketserverclient 都能主动向对方发送或接收数据。同时,WebSocket 在建立连接时需要借助 HTTP 协议,取得响应后,建立的连接会从 http 协议升级成 WebSockets 协议,以支持双向通信。WebSockets 没有同源策略,因此可以跨域通信。

    const socket = new WebSocket("ws://www.example.com/socket"); // 必须是绝对路径
    socket.send('hello');
    
    // 服务端发送消息后,触发message事件
    socket.onmessage = (event) => {
      console.log(event.data);
    };

5. Vue项目跨域开发

  • 开发阶段
    利用webpack-dev-server来代理到要跨域的服务器上。
    原理是:通过node开一个服务器进行代理。前台发向后台服务器的请求,先发向node所开的服务器,node 服务器以相同的参数向真正的服务器进行请求,再把响应返回给前台。
    //vue.config.js
    module.exports = {
      devServer: {
        proxy: {
            //   以'/api'开头的请求会被代理进行转发
            '/api': {  
                target: 'http://localhost:8081',  // 目标服务器地址   
                changeOrigin: true                     
            }
        }
      }
    }
  • 上线阶段
    利用nginx进行反向代理访问后端服务器。
    # nginx.conf
    http {
        server {
            listen       80;
            server_name  <your_server_name>;
            root /data/www;          
    
            location / {
                index  index.html; 
            }
    
            # 反向代理配置
            location /api {  
                proxy_pass <target_server>;
            }
    
        }
    }

文章作者: Snail-Lu
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Snail-Lu !
  目录