JavaScript XMLHttpRequest 同源限制及CORS杂谈

AJAX , Asynchronous JavaScript and XML 的缩写,原指的是通过 JavaScript 的异步通信,从服务器获取 XML 文档从中提取数据,再更新当前网页的对应部分,而不用刷新整个网页。

现在,服务器返回的都是JSON格式的数据,但AJAX已经成了一个通用名词,被泛化了。XMLHttpRequest对象是 AJAX 的主要接口,它实际上可以使用多种协议(比如fileftp),发送任何格式的数据(包括字符串和二进制)

# 构造实例
var xhr = new XMLHttpRequest();
#打开连接
xhr.open('GET', 'http://www.example.com/page.php', true);
# 回调监听
xhr.onreadystatechange = handleStateChange;

function handleStateChange() {
  // ...
}
# 发送请求
xhr.send(null)

AJAX 只能向同源网址(协议、域名、端口都相同)发出 HTTP 请求,如果发出跨域请求

同源限制

浏览器安全的基石是“同源政策” (same-origin policy)

最初三个相同:

协议相同
域名相同
端口相同

随着互联网的发展,同源政策越来越严格,非同源有以下三种行为受到限制

(1) 无法读取非同源网页的 Cookie、LocalStorage 和 IndexedDB。
(2) 无法接触非同源网页的 DOM。
(3) 无法向非同源地址发送 AJAX 请求(可以发送,但浏览器会拒绝接受响应)。

AJAX请求如何跨域

  • JSONP

    只能发GET请求

function addScriptTag(src) {
  var script = document.createElement('script');
  script.setAttribute('type', 'text/javascript');
  script.src = src;
  document.body.appendChild(script);
}

window.onload = function () {
  addScriptTag('http://example.com/ip?callback=foo');
}

function foo(data) {
  console.log('Your public IP address is: ' + data.ip);
};
  • WebSocket
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
Origin: http://example.com

正是因为有了Origin这个字段,所以 WebSocket 才没有实行同源政策。因为服务器可以根据这个字段,判断是否许可本次通信

  • CORS

    CORS 是跨源资源分享(Cross-Origin Resource Sharing)的缩写。它是 W3C 标准,属于跨源 AJAX 请求的根本解决方法

CORS

CORS 需要浏览器和服务器同时支持,整个通信过程,都是浏览器自动完成。与普通AJAX通信没有差别,代码完全一样。浏览器一旦发现 AJAX 请求跨域,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感知。因此,实现 CORS 通信的关键是服务器。只要服务器实现了 CORS 接口,就可以跨域通信

  • 简单请求
  • 非简单请求

    CORS 与 JSONP 的使用目的相同,但是比 JSONP 更强大。JSONP 只支持GET请求,CORS 支持所有类型的 HTTP 请求。JSONP 的优势在于支持老式浏览器,以及可以向不支持 CORS 的网站请求数据。