Cross-domain Ajax with Cross-Origin Resource Sharing
A couple of years ago, web developers were banging their head against the first wall in Ajax: the same-origin policy. While we marveled at the giant step forward enabled by cross-browser support for the XMLHttpRequest
object, we quickly bemoaned the fact that there was no way to make a request to a different domain from JavaScript. Everyone setup proxies on their web sites, which was the onset of a new host of open redirect problems, as a way to get around the restriction. Although developers were working around this limitation using server-side proxies as well as other techniques, the community outcry was around allowing native cross-domain Ajax requests. A lot of people are unaware that almost all browsers (Internet Explorer 8+, Firefox 3.5+, Safari 4+, and Chrome) presently support cross-domain Ajax via a protocol called Cross-Origin Resource Sharing.
Cross-Origin Resource Sharing (CORS)
Cross-Origin Resource Sharing (CORS) is a W3C Working Draft that defines how the browser and server must communicate when accessing sources across origins. The basic idea behind CORS is to use custom HTTP headers to allow both the browser and the server to know enough about each other to determine if the request or response should succeed or fail.
For a simple request, one that uses either GET or POST with no custom headers and whose body is text/plain
, the request is sent with an extra header called Origin
. The Origin
header contains the origin (protocol, domain name, and port) of the requesting page so that the server can easily determine whether or not it should serve a response. An example Origin
header might look like this:
Origin: http://www.nczonline.net
If the server decides that the request should be allowed, it sends a Access-Control-Allow-Origin
header echoing back the same origin that was sent or “*” if it’s a public resource. For example:
Access-Control-Allow-Origin: http://www.nczonline.net
If this header is missing, or the origins don’t match, then the browser disallows the request. If all is well, then the browser processes the request. Note that neither the requests nor responses include cookie information.
All of the previously mentioned browsers support these simple requests. Firefox 3.5+, Safari 4+, and Chrome all support usage through the XMLHttpRequest
object. When attempting to open a resource on a different origin, this behavior automatically gets triggered without any extra code. For example:
var xhr = new XMLHttpRequest();
xhr.open("get", "http://www.nczonline.net/some_resource/", true);
xhr.onload = function(){ //instead of onreadystatechange
//do something
};
xhr.send(null);
To do the same in Internet Explorer 8, you’ll need to use the XDomainRequest
object in the same manner:
var xdr = new XDomainRequest();
xdr.open("get", "http://www.nczonline.net/some_resource/");
xdr.onload = function(){
//do something
};
xdr.send();
The Mozilla team suggests in their post about CORS that you should check for the existence of the withCredentials
property to determine if the browser supports CORS via XHR. You can then couple with the existence of the XDomainRequest
object to cover all browsers:
function createCORSRequest(method, url){
var xhr = new XMLHttpRequest();
if ("withCredentials" in xhr){
xhr.open(method, url, true);
} else if (typeof XDomainRequest != "undefined"){
xhr = new XDomainRequest();
xhr.open(method, url);
} else {
xhr = null;
}
return xhr;
}
var request = createCORSRequest("get", "http://www.nczonline.net/");
if (request){
request.onload = function(){
//do something with request.responseText
};
request.send();
}
The XMLHttpRequest
object in Firefox, Safari, and Chrome has similar enough interfaces to the IE XDomainRequest
object that this pattern works fairly well. The common interface properties/methods are:
-
abort()
– use to stop a request that’s already in progress. -
onerror
– use instead ofonreadystatechange
to detect errors. -
onload
– use instead ofonreadystatechange
to detect successes. -
responseText
– use to get contents of response. -
send()
– use to send the request.
Preflighted requests
CORS allows the use of custom headers, methods other than GET or POST, and different body content types through a transparent mechanism of server verification called preflighted requests. When you try to make a request with one of the advanced options, a “preflight” request is made to the server. This request uses the OPTIONS method and sends the following headers:
-
Origin
– same as in simple requests. -
Access-Control-Request-Method
– the method that the request wants to use. -
Access-Control-Request-Headers
– (Optional) a comma separated list of the custom headers being used.
Example assuming a POST request with a custom header called NCZ
:
Origin: http://www.nczonline.net
Access-Control-Request-Method: POST
Access-Control-Request-Headers: NCZ
During this request, the server can determine whether or not it will allow requests of this type. The server communicates this to the browser by sending the following headers in the response:
-
Access-Control-Allow-Origin
– same as in simple requests. -
Access-Control-Allow-Methods
– a comma separated list of allowed methods. -
Access-Control-Allow-Headers
– a comma separated list of headers that the server will allow. -
Access-Control-Max-Age
– the amount of time in seconds that this preflight request should be cached for.
Example:
Access-Control-Allow-Origin: http://www.nczonline.net
Access-Control-Allow-Methods: POST, GET
Access-Control-Allow-Headers: NCZ
Access-Control-Max-Age: 1728000
Once a preflight request has been made, the result is cached for the period of time specified in the response; you’ll only incur the cost of an extra HTTP request the first time a request of this type is made.
Firefox 3.5+, Safari 4+, and Chrome all support preflighted requests; Internet Explorer 8 does not.
Credentialed requests
By default, cross-origin requests do not provide credentials (cookies, HTTP authentication, and client-side SSL certificates). You can specify that a request should send credentials by setting the withCredentials
property to true. If the server allow credentialed requests, then it responds with the following HTTP header:
Access-Control-Allow-Credentials: true
If a credentialed request is sent and this header is not sent as part of the response, then the browser doesn’t pass the response to JavaScript (responseText
is an empty string, status
is 0, and onerror()
is invoked). Note that the server can also send this HTTP header as part of the preflight response to indicate that the origin is allowed to send credentialed requests.
Internet Explorer 8 doesn’t support the withCredentials
property; Firefox 3.5, Safari 4, and Chrome all support it.
Conclusion
There is a lot of solid support for cross-domain Ajax in modern web browsers, yet most developers are still unaware of this powerful capability. Usage requires just a little bit of extra JavaScript work and a little extra server-side work to ensure that the correct headers are being sent. IE8′s implementation lags a bit behind the others in terms of allowing advanced requests and credentialed requests, but hopefully support for CORS will continue to improve. If you’d like to learn more, I highly suggest checking out Arun Ranganathan’s examples page.
Update (25 May 2010): Fixed typo in example code.
Update (27 May 2010): Removed trailing slash from Origin headers.
Disclaimer: Any viewpoints and opinions expressed in this article are those of Nicholas C. Zakas and do not, in any way, reflect those of my employer, my colleagues, Wrox Publishing, O'Reilly Publishing, or anyone else. I speak only for myself, not for them.
相关推荐
《刀架溜板ZZ027-A):深入解析三维设计技术在机械工程中的应用》 在现代工业设计中,三维设计技术已经成为不可或缺的一部分。本文将深入探讨标题为“刀架溜板ZZ027-A)”的压缩包文件,该文件包含的产品三维设计图,...
《中医大夫助理信息系统 zz-doctor 深度解析》 中医大夫助理信息系统“zz-doctor”是一款基于Android平台的应用程序,旨在为中医医生提供智能化、便捷化的诊疗辅助工具。通过深入剖析这款应用的源码,我们可以了解...
标题“机械毕业设计——刀架溜板ZZ027-A).zip”暗示了这是一个与机械工程相关的毕业设计项目,重点是刀架溜板ZZ027-A的设计。刀架溜板是机床的重要组成部分,通常在车床或铣床上用于安装和移动刀具,以实现对工件的...
《SpringBoot2深度解析——基于atguigu_springboot2_zz-master项目实践》 SpringBoot作为现代化Java开发的重要框架,极大地简化了Spring应用的初始搭建以及开发过程。本篇文章将深入探讨基于`atguigu_springboot2_...
zz1165935664-BLab-master_zzk3686_pcb_esp8266电路_esp8266电路板_模块pcb_源码.zip
这个赛题,即“ZZ-2022010 机器人技术应用赛项”,是针对这一目标而设立的竞赛项目。 赛题通常涵盖以下几个核心知识点: 1. **机器人基础知识**:参赛者需要了解机器人的基本构成,包括机械结构、电子元件、传感器...
ZZ-2021030 网络搭建与应用赛项赛卷《网络环境》.pdf
ZZ-2022004 建筑CAD赛项赛题 中职赛项 适合正在准备技能大赛的人群
ZZ-2022022 汽车机电维修赛项赛题 中职赛项 适合正在准备技能大赛的人群
VIM(Vi IMproved)是Linux世界中广受欢迎的文本编辑器,对于程序员来说,它不仅是一个工具,更是一种高效的工作方式。这篇文章将深入探讨VIM的使用技巧和重要概念,帮助你提升编辑效率。 首先,VIM的操作模式是其...
ZZ030-2018年安徽省职业院校技能大赛中职组“汽车营销”赛项规程.doc.pdf
标题中的“zz1165935664-BLab-master_zzk3686_pcb_esp8266电路_esp8266电路板_模块pcb”暗示了这是一个关于电子工程项目的资源,特别是与ESP8266微控制器相关的电路板设计。ESP8266是一款经济实惠且功能强大的Wi-Fi...
介绍了ZZ2-8/100型钻装机的结构组成及功能,针对其功能要求,设计了钻装机的液压系统,阐述了该液压系统中泵站、控制回路、行走回路、扒装回路和左/右钻臂回路的工作过程。实践表明该液压系统具有功能互锁、防卡钎、...
电子商务技能赛项规程是为2021年全国职业院校技能大赛所制定的规则与指引,其内容涵盖了竞赛的整个流程,包括赛项的宗旨、竞赛内容与分值、竞赛方式、竞赛流程等。本赛项旨在考察选手在电子商务领域的多项技能,包括...
总结了ZZ2-8/100型钻装机在攀煤集团大宝鼎煤矿+1220 m水平南翼运输巷的工业试验情况,对试验中钻装机凿岩、扒装及排矸等工作情况进行了介绍,并对试验中暴露的问题进行了分析,为钻装机的改进设计以及煤矿岩巷机械化...
【标题】: "Last ZZ50 - MetaTrader 5 EA" 【内容】: "Last ZZ50" 是一款专为MetaTrader 5 (MT5) 平台设计的自动交易专家顾问(EA),它利用了之字转向(ZZS pivot)指标与挂单策略相结合的交易逻辑。MetaTrader 5...