浏览器与服务器通信技术——跨域资源共享
由于同源策略限制,默认情况下,使用XHR对象只能访问与包含它的页面位于同一个域(相同的协议、域名和端口)中的资源。要实现合理的跨域资源请求,有两种策略:1.跨域资源共享 ,2.利用DOM中能够执行跨域请求的功能。本文详述了第一种策略的实现方法。
跨域资源共享(CORS)背后的基本思想,就是使用自定义的HTTP头部让浏览器与服务器进行沟通,从而决定请求或相应是应该成功,还是应该失败。这种方法需要修改服务器代码。
一. 简单请求的情况
如果只是简单的使用GET或POST发送请求,并且没有自定义的头部,且主体内容是text/plain。在发送该请求时,需附加一个额外的origin头部,其中包含请求页面的源信息(协议、域名和端口),服务器会根据这个头部信息来决定是否给与响应。头部实例如下:
origin:http://www.snsartme.com
大部分浏览器都通过XMLHttpRequest对象实现了CORS的原生支持。在访问不同域的资源时,无需额外编写代码就会自动发送origin头部。只需要在open()方法中传入绝对URL即可,例如:
1 var xhr=new XMLHttpRequest(); 2 xhr.onreadystatechange=function(){ 3 if(xhr.readyState==4){ 4 if((xhr.status>=200&&xhr.status<300)||xhr.status==304){ 5 alert("成功"+xhr.responseText); 6 }else{ 7 alert("失败"+xhr.responseText); 8 } 9 } 10 }; 11 12 xhr.open("get","http://www.somewhere.com/test.php",true); 13 xhr.send(null);
如果服务器认为这个请求可以接受,就会在Access-Control-Allow-origin头部中回发相同的源信息(如果是公共资源,可以回发 ‘ * ’),比如在服务器的php代码中加入以下代码,来发送Access-Control-Allow-origin头部:
header('Access-Control-Allow-origin:http:/www.snsartme.com');
简单请求有如下一些限制:
1. 不能使用setRequestHeader()方法设置自定义头部。
2. 不能发送和接受cookie。
3. 调用getALLResponseHeaders()方法总会返回空字符串。
二、 预检请求
预检请求(Preflighted Requests)必须首先使用OPTIONS方法发起一个预检请求到服务器,以获知服务器是否允许该实际请求。“预检请求”的使用,可以避免跨域请求对服务器的用户数据产生无法预知的影响。OPTIONS方法发出的请求头部如下:
Origin:与简单的请求相同。
Access-Control-Request-Method:请求使用的方法
Access-Control-Request-Headers:自定义的头部信息,多个头部以逗号分隔。
当使用setRequestHeader()方法设置了自定义头部,或者请求方法不是get或post时,就会自动发送预检请求:
1 var xhr=new XMLHttpRequest(); 2 xhr.open("get","http://www.somewhere.com/test.php",true); 3 xhr.setRequestHeader("x-token", "I am x-token"); 4 xhr.send(null);
服务器通过在响应中发送如下头部信息与浏览器沟通,php代码如下:
1 header('Access-Control-Allow-origin:http://www.snsartme.com'); 2 header('Access-Control-Allow-Methods: GET,POST');//允许的方法 3 header('Access-Control-Allow-Headers:x-token'); //允许的头部 4 header('Access-Control-Max-Age:7800'); //应该将预检请求缓存多长时间
三、带凭据的请求
默认情况下,跨域请求不提供凭据(cookie,HTTP认证及客户端SSL证明等)。通过将xhr的withCredentials属性设置为true,可以指定某个请求应该发送凭据。如果服务器接送带凭据的请求,会用下面的HTTP头部来响应。
header('Access-Control-Allow-Credentials: true');
下一篇会详解利用DOM中能够执行跨域请求的功能实现跨域资源访问,主要是jsonp技术