ajax请求数据出现跨域的原因: 浏览器的‘同源策略’。(同源: 协议,域名,端口)
浏览器的同源策略目的:是为了保护用户信息安全,防止恶意网站窃取数据。
由同源策略导致限制:
1)Cookie、LocalStorage和IndexDB无法读取。
2)DOM无法获取
3)AJAX请求不能发送。
如何解决上述限制呢?
1)Cookie
Cookie是服务器写入浏览器的一小段信息,只有同源的网页才能共享。但是,两个网页一级域名相同,只是二级域名不同,浏览器允许通过设置document.domain共享Cookie。
LocalStorage 和 IndexDB 使用POSTMessage API。
2)AJAX请求
除了假设服务器代理(浏览器请求同源服务器,再由后者请求外部服务),有三种方法规避这个限制。
①JSONP
基本思想:网页通过添加一个<script>元素,向服务器请求JSON数据,这种做法不受同源政策限制;服务器收到请求后,将数据放在一个指定名字的回调函数里传回来。
function addScriptTag(src){
var script= document.createElement('script');
script.setAttribute('type','text/javascript');
script.src= src;
document.body.appendChild(script);
}
function foo(data){
console.log('get Data '+ data);
}
window.onload = function(){
addScriptTag('http://www.sun.com/a.html?callback=foo');
}
②WebSocket
WebSocket是一种通信协议,使用ws://(非加密)和wss://(加密)作为协议前缀。该协议不实行同源策略,只要服务器支持,就可以通过他进行跨源通信。
案例:
浏览器发出的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,如果该域名在白名单内,服务器就会做出如下回应:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
Sec-WebSocket-Protocol: chat
③CORS
CORS是跨域资源分享(Cross-Origin Resource Sharing)。相比JSONP只能发GET请求,CORS允许任何类型的请求。
实现cors关键在于服务器,因为基本浏览器都支持该功能并且自动完成。
浏览器将CORS请求分成两类: 简单请求和非简单请求
第一种:简单请求
只要同时满足一下两大条件,就属于简单请求:
1)请求方式: head,get,post
2)HTTP头信息不超出以下几种字段:
*Accept
*Accept-Language
*Content-Language
*Last-Event-ID
*Content-Type: 只限于三个值 application/x-www-form-urlencoded,multipart/form-data,text/plain
针对简单请求处理流程:
1)自动在头信息中添加一个Origin字段。
如果,不在许可范围内,服务器返回一个正常的HTTP响应。但是不包含Access-Control-Allow-Origin字段就显示出现。
如果,在许可范围内,服务器返回的响应会多出几个头信息字段。
Access-Control-Allow-Origin:(接受哪些域名的请求)
Access-Control-Allow-Credentials: true(是否允许在请求中发送Cookie)
Access-Control-Expose-Headers: FooBar
Content-Type: text/html;charset=utf-8
2)withCredentials属性
CORS请求默认不发送Cookie和HTTP认证信息。如果要把Cookie发送到服务器,
需设置两个地方:
①服务器同意: Access-Control-Allow-Credentials: true
② 开发者必须在AJAX请求中打开withCredentials属性。
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;