跨域

跨域

定义

跨域:指一个 domain 下的 HTML 或脚本试图去请求另一个 domain 下的资源。

同源策略

同源策略 (Same origin policy):两个 URL 的协议、域名、端口相同。

同源限制访问资源

  • CookieLocalStorageIndexDB 无法读取
  • DOMJs 对象无法获得
  • AJAX 请求不能发送

JSONP

<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>

后端返回的内容如下所示,即返回后立即执行 handleCallback

handleCallback({"status": true, "user": "admin"})

JSONP 只能进行 GET 调用

跨域资源共享 (CORS)

服务端设置 Access-Control-Allow-Origin:* 头即可,前端无须设置。如果想要进行 cookie 的读写,那么前端需要设置这个属性为 true

var xhr = new XMLHttpRequest();
// 前端开关:浏览器是否读写cookie
xhr.withCredentials = true;

预请求 (preflight)

(1)为什么需要预请求

为了让浏览器知道,它所请求的服务器是一个对 CORS 有感知 (CORS-aware) 的服务器,也就是说让浏览器知道这个服务器是能够对 CORS 做出正确处理的服务器。

(2)触发方式

浏览器发送 OPTIONS 请求。

(3)触发 规则

  • 简单请求(GETHEADPOST)并且没有设置 force preflight flag 位,那么不触发

WebSocket

WebSocket 协议允许跨域通信

心跳怎么实现的

任意一方,都可以发送 ping/pong control frame 来检测是否还处于连接状态。

postMessage

这是 HTML5 XMLHttpRequest Level 2 引入的新的 API,可以用于前端多个打开的窗口之间的数据传递

A 网站发送消息给 B 网站

<iframe src="http://a.com" name="a">

<script>
  let a = window.frames.a;
  a.postMessage("message", "http://b.com");
</script>

B 网站接受消息

window.addEventListener("message", function(event) {
  if (event.origin != 'http://a.com') {
    // something from an unknown domain, let's ignore it
    return;
  }

  alert( "received: " + event.data );

  // can message back using event.source.postMessage(...)
});

代理

直接访问 login 和 api 域名

通过代理访问 login 和 api 域名

代理服务器可以设置上 Access-Control-Allow-Origin:* 这个响应头,taobao.com 需要访问 api.taobao.comlogin.taobao.com 上的资源,就请求代理服务器去访问,代理服务器作为中间人,在中间帮助转发请求和响应。

通过代理访问资源,需要重写 URL 和进行 URL 访问映射:

  • 之前访问的是 api.taobao.com,现在改为访问 proxy.taobao.com/api,代理服务器收到这个请求后,再去请求 api.taobao.com,并将响应转发给 taobao.com
  • 请求 login.taobao.com 也是同样的道理,同样可以将 URL 改为 proxy.taobao.com/login

这个代理服务器,可以是流行的 Nginx 代理服务器,也可以是其他的用于转发请求和响应的服务器,这个代理服务器可以拦截流量,可以添加自定义头,可以统计信息等,总之针对浏览器限制的行为在服务器端是不受限制的。

跨域是浏览器的行为,不是服务器的行为。

参考