跨域及解决

same-origin policy(SOP)限制浏览器中脚本只能获取同域下的资源和数据。

跨域只限制从脚本中对资源发起的访问,页面中标签加载资源是不受限制的。

跨域的定义

以下来自维基百科的表格很好地展示了怎样算是跨域,以 http://www.example.com/dir/page.html 作为基准进行判断时,

Compared URL Outcome Reason
http://www.example.com/dir/page2.html 成功 相同格式, 主机及端口
http://www.example.com/dir2/other.html 成功 相同格式, 主机及端口
http://username:password@www.example.com/dir2/other.html 成功 相同格式, 主机及端口
http://www.example.com:81/dir/other.html 失败 相同格式及主机但端口不同
https://www.example.com/dir/other.html 失败 格式不同
http://en.example.com/dir/other.html 失败 不同主机
http://example.com/dir/other.html 失败 不同主机 (需要严格匹配)
http://v2.www.example.com/dir/other.html 失败 不同主机 (需要严格匹配)
http://www.example.com:80/dir/other.html 看情况 此处端口被显式指明,依赖浏览器的实现而表现不一

其中:

  • 主机(host)
  • 格式(URI scheme)

解决办法

服务器配置跨域控制头

服务器配置相应的跨域控制头以允许相应站点对资源的访问。

Access-Control-Allow-Origin: *
Access-Control-Allow-Origin: http://www.example.com

此过程浏览器可能会预先发送一个 OPTION 的 preflight 请求到服务器,并带上 Origin 请求头:

OPTIONS /
Host: service.example.com
Origin: http://www.example.com

服务器允许该域,则返回:

Access-Control-Allow-Origin: http://www.example.com
Access-Control-Allow-Methods: PUT, DELETE

代理

将跨域资源走服务器代理,因为从服务器访问是不受跨域限制的。

JSONP

复用跨域只限制从脚本中对资源发起的访问,页面中标签加载资源是不受限制这一特征,可以将跨域的接口用 JSONP(JSON with Padding) 方式来处理。

原理页面中创建 script 标签加载对应的接口,接口返回的文本中包含 js 函数的调用及封装好的数据入参。

示例:

<script>
function callback(data){
    console.log(data)
}
</script>
<script src="http://example/api/foo"></script>

其中 http://example/api/foo 返回文本 callback("hello") 会以脚本形式被浏览器执行,完成了数据的获取。

通过配置 Access-Control-Allow-Origin 解决了跨域请求,但跨域情况下默认是不会带 Cookie 的。

如果需要跨域发送 Cookie,需要端上面发起异步请求时设置 withCredentials: true

原生 JavaScript

var xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.withCredentials = true;
xhr.send();

jQuery

$.ajax({
   url: a_cross_domain_url,
   xhrFields: {
      withCredentials: true
   }
});

同时,需要服务器配置 Access-Control-Allow-Credentialstrue,否则即使 Cookie 被成功发送也不会被接收。

另外,在配置了 Access-Control-Allow-Credentials: true 时,Access-Control-Allow-Origin 不能使用通配符,必需指定单一的源。

相关资源