浏览器与服务器通信技术——跨域资源共享

由于同源策略限制,默认情况下,使用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技术

 

posted @ 2019-05-22 18:06  snsart  阅读(636)  评论(0编辑  收藏  举报