如何实现跨域?多种跨域方案介绍

什么是跨域?

跨域,是指浏览器不能执行其他网站的脚本。它是由浏览器的同源策略导致的,是浏览器对 JavaScript 实施的安全限制。

同源策略是一个重要的安全策略,它用于限制一个 origin 的文档或者它加载的脚本如何能与另一个源的资源进行交互。它能帮助阻隔恶意文档,减少可能被攻击的媒介。-- MDN

只有当域名、协议、端口三者一致时,才是同源。

同源才不会受到浏览器的同源策略限制,否则就需要跨域。

最经典的跨域方案 JSONP

jsonp 的原理是利用<script>标签不受同源策略限制的特性来进行跨域操作。但它只能用来发送 GET 请求。

在客户端和服务端定义一个函数,当客户端发起一个请求时,服务端返回一段 javascript 代码,其中调用了在客户端定义的函数,并将相应的数据作为参数传入该函数。

function jsonp_cb(data) {
  console.log(data);
}

function ajax() {
  var url = 'http://xx.com/test.php?jsonp_callback=jsonp_cb';
  var script = document.createElement('script');
  // 发送请求
  script.src = url;
  document.head.appendChild(script);
}
ajax();

服务端获取到 jsonp_callback 传递的函数名 jsonp_cb,返回一段对该函数调用的 js 代码

jsonp_cb({
  name: 'story',
});

最流行的跨域方案 CORS

CORS(跨域资源共享)是一种跨域访问的机制,可以让 AJAX 实现跨域访问。它允许一个域上的脚本向另一个域提交跨域 AJAX 请求。实现此功能非常简单,只需由服务器发送一个响应头即可。

Access-Control-Allow-Origin: * // 允许来自任何域的请求,不安全
Access-Control-Allow-Origin: https://arvinxiang.com/ // 仅允许来自特定域的请求

当客户端的 ajax 请求的 url 为其他域时,对于支持 CORS 的浏览器,请求头会自动添加 Origin,值为当前 host。

var xhr = new XMLHttpRequest();
var url = 'http://bar.other/resources/public-data/';
xhr.open('GET', url, true);
xhr.send();

CORS 默认不发送 cookie,如果要发送 cookie,需要设置 withCredentials

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

同时,服务端也要设置

Access-Control-Allow-Credentials: true

最方便的跨域方案 Nginx

nginx 作为代理服务器将请求转发给后端服务,这样就规避了同源策略。

在网站的配置文件里增加以下配置:

location / {
    add_header Access-Control-Allow-Origin *;
    add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
    add_header Access-Control-Allow-Headers 'Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';

    if ($request_method = 'OPTIONS') {
        return 204;
    }
}

img ping

img 标签也是没有跨域限制的,但它只能用来发送 GET 请求,且无法获取服务端的响应文本,可以利用它实现一些简单的、单向的跨域通信,常用于数据上报

var img = new Image();
img.onload = function () {
  console.log('done');
  img.onload = null;
  img = null;
};
img.src = 'http://xx/xx.gif';

其他跨域方案

  • window.name + iframe
  • location.hash + iframe
  • document.domain + iframe
  • window.postMessage
  • websocket

参考

https://www.ruanyifeng.com/blog/2016/04/cors.html https://developer.mozilla.org/zh-CN/docs/Web/API/Window/postMessage https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS https://livebook.manning.com/book/cors-in-action/chapter-6/262

© 2022  Arvin Xiang
Built with ❤️ by myself