由于同源策略限制, 默认情况下, 使用 XHR 对象只能访问与包含它的页面位于同一个域 (相同的协议, 域名和端口) 中的资源. 要实现合理的跨域资源请求, 有两种策略: 1. 跨域资源共享 ,2. 利用 DOM 中能够执行跨域请求的功能. 本文详述了第一种策略的实现方法.
跨域资源共享 (CORS) 背后的基本思想, 就是使用自定义的 HTTP 头部让浏览器与服务器进行沟通, 从而决定请求或相应是应该成功, 还是应该失败. 这种方法需要修改服务器代码.
一. 简单请求的情况
如果只是简单的使用 GET 或 POST 发送请求, 并且没有自定义的头部, 且主体内容是 text/plain. 在发送该请求时, 需附加一个额外的 origin 头部, 其中包含请求页面的源信息(协议, 域名和端口), 服务器会根据这个头部信息来决定是否给与响应. 头部实例如下:
origin:http://www.snsartme.com
大部分浏览器都通过 XMLHttpRequest 对象实现了 CORS 的原生支持. 在访问不同域的资源时, 无需额外编写代码就会自动发送 origin 头部. 只需要在 open()方法中传入绝对 URL 即可, 例如:
- var xhr=new XMLHttpRequest();
- xhr.onreadystatechange=function(){
- if(xhr.readyState==4){
- if((xhr.status>=200&&xhr.status<300)||xhr.status==304){
- alert("成功"+xhr.responseText);
- }else{
- alert("失败"+xhr.responseText);
- }
- }
- };
- xhr.open("get","http://www.somewhere.com/test.php",true);
- 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 时, 就会自动发送预检请求:
- var xhr=new XMLHttpRequest();
- xhr.open("get","http://www.somewhere.com/test.php",true);
- xhr.setRequestHeader("x-token", "I am x-token");
- xhr.send(null);
服务器通过在响应中发送如下头部信息与浏览器沟通, PHP 代码如下:
- header('Access-Control-Allow-origin:http://www.snsartme.com');
- header('Access-Control-Allow-Methods: GET,POST');// 允许的方法
- header('Access-Control-Allow-Headers:x-token'); // 允许的头部
- header('Access-Control-Max-Age:7800'); // 应该将预检请求缓存多长时间
三, 带凭据的请求
默认情况下, 跨域请求不提供凭据(cookie,HTTP 认证及客户端 SSL 证明等). 通过将 xhr 的 withCredentials 属性设置为 true, 可以指定某个请求应该发送凭据. 如果服务器接送带凭据的请求, 会用下面的 HTTP 头部来响应.
header('Access-Control-Allow-Credentials: true');
下一篇会详解利用 DOM 中能够执行跨域请求的功能实现跨域资源访问, 主要是 JSONP 技术
来源: https://www.cnblogs.com/snsart/p/10907615.html