跨域处理

38 阅读2分钟

浏览器的同源策略

同源策略是一个重要的安全策略,他用于限制不同的源之间的资源不能进行交互。主要目的是为了阻隔恶意文档,减少可能被攻击的媒介。

如何允许跨源访问

CORS

CORS是HTTP的一部分,它允许服务端来指定哪些主机可以从这个服务端加载资源。跨源资源共享 (CORS)是一种基于 HTTP 头的机制,该机制通过允许服务器标示除了它自己以外的其它 origin(域,协议和端口),使得浏览器允许这些 origin 访问加载自己的资源。跨源资源共享还通过一种机制来检查服务器是否会允许要发送的真实请求,该机制通过浏览器发起一个到服务器托管的跨源资源的"预检"请求。在预检中,浏览器发送的头中标示有 HTTP 方法和真实请求中会用到的头。

HTTP响应首部字段

Access-Control-Allow-Origin

配置的参数指定了允许访问该资源的外域URI,也可以用*号表示通配符,允许来自所有其他域的请求

预检请求OPTIONS

一个CORS预检请求(preflight request)用于检查服务器是否支持CORS。
检单请求像GET,HEAD,POST并并不会触发预检请求。

Access-Control-Request-Headers

用于通知服务器真正的请求中会采用哪些请求头

Access-Control-Allow-Methods

用于通知服务器真正的请求中会采用哪个请求方法。

Access-Control-Max-Age

预检请求返回的结果会缓存的最长时间,代表在改时间段内预检请求不会发起第二次,超时才会去发起第二次请求。

JSONP

ajax受同源策略的影响,不允许跨域请求,但是在script标签src属性中的链接可以访问跨域的JS脚本,利用这个特性:
服务端可以返回一段调用callback函数的js代码,在src中调用从而实现跨域。

手写一个jsonp

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>JSONP</title>
    <script>
      function myJSONP(options) {
        if (!window.callbackName) {
          window.callbackName = 1;
        } else {
          window.callbackName++;
        }
        let { url, type, dataType, success, data } = options;
        let fullName = "jsonpReceive" + window.callbackName;
        function clear() {
          window[fullName] = null;
          script.parentNode.removeChild(script);
          clearTimeout(timer);
        }
        window[fullName] = function(result) {
          success(result);
          clear();
        };
        let timer = setTimeout(() => {
          clear();
        }, 5000);
        let params = "";
        if (Object.keys(data).length) {
          for (let key in data) {
            params += `&${key}=${encodeURIComponent(data[key])}`;
          }
          params = params.substr(1);
        }
        url = `${url}?${params}&callback=${fullName}`;
        let script = document.createElement("script");
        script.src = url;
        document.body.appendChild(script);
      }
    </script>
  </head>
  <body>
    <script>
      myJSONP({
        type: "get",
        url: url,
        dataType: "jsonp",
        data: {
          a: 1,
        },
        success(res) {
          console.log(res);
        },
      });
    </script>
  </body>
</html>

jsonp 后台nodejs的版本

const http = require("http");
const url = require("url");

http
  .createServer(function(request, response) {
    const urlObj = url.parse(request.url, true);
    let data = { name: "JACK", age: 18 };
    response.end(`${urlObj.query.callback}(${JSON.stringify(data)})`);
  })
  .listen(7777);

服务器中转(重定向)

因为服务器之间调用不存在跨域的问题,所以可以通过如nginx实现代理转发实现同域访问。