浏览器同源策略 & 跨域解决方案

279 阅读3分钟

源(Origin)是由 URL 中协议、主机名(域名 domain)以及端口共同组成的部分,协议、主机名(域名或 IP)、端口号相同则视为同源。否则则为跨源 当一个源访问另一个源的资源时就会产生跨源。同源策略就是用来限制其中一些跨源访问的,包括访问 iframe 中的页面、其他页面的 cookie 访问以及发送 AJAX 请求。最常见的跨源场景是域名不同,即常说的“跨域”。 同源策略在保障安全的同时也带来了不少问题,比如 iframe 中的子页面与父页面无法通信,浏览器与其他服务端无法交互数据

跨域解决方案

  1. 跨域资源共享

    跨域资源共享(CORS,Cross-Origin Resource Sharing)是浏览器为 AJAX 请求设置的一种跨域机制,让其可以在服务端允许的情况下进行跨域访问。主要通过 HTTP 响应头来告诉浏览器服务端是否允许当前域的脚本进行跨域访问。

    解决方案: 以 nodeJs 为例,可在接口响应头中配置以下字段,允许 http://localhost:3000 这个域响应,也可将Access-Control-Allow-Origin的值配置为'*'允许所有响应

    res.header('Access-Control-Allow-Origin', 'http://localhost:3000');
    res.header('Access-Control-Allow-Methods', 'PUT,POST,GET,DELETE,OPTIONS');
    res.header(
      'Access-Control-Allow-Headers',
      'Content-Type,Content-Length, Authorization, Accept,X-Requested-With'
    );
    
  2. jsonp(动态创建 script 标签)

    前端定义 callback 查询参数,值为回调函数名称,后端将响应数据作为回调函数的参数传回,页面接收到时会立即执行代码

    解决方案:jsonp

  3. websocket

    Websocket 是 HTML5 规范提出的一个应用层的全双工协议,适用于浏览器与服务器进行实时通信场景。 什么叫全双工呢? 这是通信传输的一个术语,这里的“工”指的是通信方向,“双工”是指从客户端到服务端,以及从服务端到客户端两个方向都可以通信,“全”指的是通信双方可以同时向对方发送数据。与之相对应的还有半双工和单工,半双工指的是双方可以互相向对方发送数据,但双方不能同时发送,单工则指的是数据只能从一方发送到另一方。 下面是一段简单的示例代码。在 a 网站直接创建一个 WebSocket 连接,连接到 b 网站即可,然后调用 WebScoket 实例 ws 的 send() 函数向服务端发送消息,监听实例 ws 的 onmessage 事件得到响应内容。

    var ws = new WebSocket('ws://b.com');
    ws.onopen = function () {
      // ws.send(...);
    };
    ws.onmessage = function (e) {
      // console.log(e.data);
    };
    
  4. 代理转发

    跨域是为了突破浏览器的同源策略限制,既然同源策略只存在于浏览器,那可以换个思路,在服务端进行跨域,比如设置代理转发。这种在服务端设置的代理称为“反向代理”,对于用户而言是无感知的。 另一种在客户端使用的代理称为“正向代理”,主要用来代理客户端发送请求,用户使用时必须配置代理服务器的网址,比如常用的 VPN 工具就属于正向代理。 代理转发实现起来非常简单,在当前被访问的服务器配置一个请求转发规则就行了。

    • webpack proxy 配置
    // webpack.config.js
    module.exports = {
      //...
      devServer: {
        proxy: {
          '/api': 'http://localhost:3000',
        },
      },
    };
    
    • nginx 的 proxy_pass
     location /api {
     proxy_pass   http://localhost:3000;
    }
    
    

    总结

    作为前端开发理解浏览器的同源策略有助于更进一步的了解浏览器与服务器之间的通信关系。前端开发平时只与页面UI打交道往往是不够的,还是应该向后走,多理解下底层实现,将网页渲染,网络通信的链路进行打通。最终实现软件开发的整个工程都能了然于胸。这样即使在新框架,新的编程思想层出不穷的前端领域,也能够站稳脚跟