title: 跨域请求 date: 2019-12-26 14:00:00 tabs:
- CORS
- 跨域
- JavaScript categories: Web前端 urlname: cross-domain-request
CORS(Cross-Origin Resource Sharing,跨源资源共享)是 W3C 的一个工作草案,定义了在必须访 问跨源资源时,浏览器与服务器应该如何沟通。
CORS
基本思想
-
使用自定义的HTTP头部让浏览器和服务器进行沟通,比如给一个GET或者POST请求添加一个额外的Origin头部, 其中包含请求页面的
源信息(协议、域名和端口)。如:Origin: www.baidu.com
-
如果服务器认为这个请求可以接受,就在Access-Control-Allow-Origin头部中回发相同的源信息或者
*。如:Access-Control-Allow-Origin: www.baidu.com
-
如果没有这个头部或者有这个头部但源信息不匹配,浏览器就会驳回请求。
IE对CORS的实现
在IE8引入了XDR(XDomainRequest)类型,与XHR类似,主要有以下不同:
- cookie不会随请求发送,也不会随相应返回。
- 只能设置请求头部信息中的Content-Type字段。
- 不能访问响应头部信息。
- 只支持GET和POST请求。
其他浏览器对CORS的实现
Firefox 3.5+、Safari 4+、Chrome、iOS 版 Safari 和 Android 平台中的 WebKit 都通过 XMLHttpRequest 对象实现了对 CORS 的原生支持。
与IE中的XDR对象不同,通过跨域XHR对象可以访问status和statusText属性,还支持同步请求。但为了安全,跨域XHR对象有以下限制:
- 不能使用setRequestHeader()设置自定义头部。
- 不能发送和接收cookie。
- 调用getAllResponseHeaders()方法总会返回空字符串。
Preflighted Requests
CORS 通过一种叫做 Preflighted Requests 的透明服务器验证机制支持开发人员使用自定义的头部、
GET 或 POST 之外的方法,以及不同类型的主体内容。在使用下列高级选项来发送请求时,就会向服务
器发送一个Preflight请求。这种请求使用OPTIONS方法,不消耗任何内存和带宽,发送下列头部。
- Origin:与简单请求相同。
- Access-Control-Request-Method:请求自身使用的方法。
- Access-Control-Request-Headers:(可选)自定义的头部信息,多个头部以逗号分隔。如:
Origin: https://www.baidu.com Access-Control-Request-Method: POST Access-Control-Request-Headers: anyHeader
发送这个请求后,服务器可以决定是否允许这种类型的请求:
- Access-Control-Allow-Origin:与简单请求相同。
- Access-Control-Allow-Methods:允许的方法,多个方法以逗号分隔。
- Access-Control-Allow-Headers:允许的头部,多个头部以逗号分隔。
- Access-Control-Max-Age:应该将这个 Preflight 请求缓存多长时间(以秒表示)。
带凭据的请求
默认情况下,跨源请求不提供凭据(cookie、HTTP 认证及客户端 SSL 证明 等 )。 通 过 将 withCredentials 属性设置为 true,可以指定某个请求应该发送凭据。如果服务器接受带凭据的请 求,会用下面的 HTTP 头部来响应。
Access-Control-Allow-Credentials: true
图像Ping
一个网页可以从任何网页中加载图像而不用担心是否跨域,由此我们可以通过动态的创建图像, 使用它们的onload和onerror事件处理程序来确定是否接收到了响应。常用语跟踪用户点击 页面或动态广告曝光次数,它有以下特点:
- 仅支持GET请求。
- 响应可以是任意内容,通常是像素图或204.
- 浏览器无法得到任何具体的数据,但是可以通过load和error事件来知道响应是什么时候接收到的。
例子:
const img = new Image();
img.onload = img.onerror = () => {
console.log('Done!');
}
img.src = "https://www.baidu.com";
JSONP
JSONP 是 JSON with padding(填充式 JSON 或参数式 JSON)的简写,由两部分组成:回调函数和数据。
JSONP通过动态<script>元素来使用:
function handleResponse(response){
alert("You’re at IP address " + response.ip + ", which is in " +
response.city + ", " + response.region_name);
}
var script = document.createElement("script");
// 核心代码
script.src = "http://freegeoip.net/json/?callback=handleResponse";
document.body.insertBefore(script, document.body.firstChild);
但JSONP也有两点不足:
- 从其它域加载的js如果过含有恶意代码会造成一些安全隐患。
- 要确定JSONP请求是否失败并不容易,但HTML5给
<script>元素新增了onerror时间处理程序,可以一试。
参考
- JavaScript高级程序设计