跨域及解决
跨域及解决
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")
会以脚本形式被浏览器执行,完成了数据的获取。
跨域传 Cookie
通过配置 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-Credentials
为 true
,否则即使 Cookie 被成功发送也不会被接收。
另外,在配置了 Access-Control-Allow-Credentials: true
时,Access-Control-Allow-Origin
不能使用通配符,必需指定单一的源。