- 浏览: 312189 次
- 性别:
- 来自: 上海
文章分类
- 全部博客 (243)
- Core Java (13)
- Java (12)
- Android (2)
- Lucene (3)
- J2EE (3)
- Hibernate (2)
- Jsp & Servlet (3)
- Struts2 (3)
- Spring (5)
- JSF (6)
- RichFaces (2)
- HTML & JS & DOM & CSS (87)
- browser (1)
- Ajax & A4J (2)
- Workflow (1)
- Maven (3)
- Linux (2)
- VM & VBOX (1)
- Tomcat (1)
- Cache (3)
- Others (36)
- design (1)
- PHP (1)
- Try.js (1)
- HTML5 && CSS3 && ECMAScript5 (26)
- 疯言疯语 (5)
- mongodb (2)
- Hardware Common Sence (1)
- RESTful (3)
- Nginx (2)
- web安全 (8)
- Page Design (1)
- web performance (1)
- nodejs (4)
- python (1)
最新评论
-
New_Mao_Er:
求最新的版本破解啊!!!
Omondo eclipseUML插件破解 -
konglx:
讲得仔细,谢了
全面分析 Spring 的编程式事务管理及声明式事务管理 -
cilendeng:
对所有post有效只能使用过滤器
说说Tomcat的Server.xml的URIEncoding=‘UTF-8’配置 -
jiulingchen:
mark了,灰常感谢!
JAVA中最方便的Unicode转换方法 -
anlaetion:
这算法可以有
js 字符串搜索算法
跨域请求一直是网页编程中的一个难题,在过去,绝大多数人都倾向于使用JSONP
来解决这一问题。不过现在,我们可以考虑一下W3C中一项新的特性——CORS(Cross-Origin Resource Sharing)了。
本文的所有代码均来自http://www.html5rocks.com/en/tutorials/cors/,如果您对其中的任何技术细节存在疑问,请以原文为准。
客户端
创建XmlHttpRequest
对象
对于CORS,Chrome、FireFox以及Safari,需要使用XmlHttpRequest2
对象;而对于IE,则需要使用XDomainRequest
;Opera目前还不支持这一特性,但很快就会支持。
因此,在对象的创建上,我们不得不首先针对不同的浏览器而进行一下预处理:
function createCORSRequest(method, url) { var xhr = new XMLHttpRequest(); if ("withCredentials" in xhr) { // "withCredentials"属性是XMLHTTPRequest2中独有的 xhr.open(method, url, true); } else if (typeof XDomainRequest != "undefined") { // 检测是否XDomainRequest可用 xhr = new XDomainRequest(); xhr.open(method, url); } else { // 看起来CORS根本不被支持 xhr = null; } return xhr; } var xhr = createCORSRequest('GET', url); if (!xhr) { throw new Error('CORS not supported'); }
事件处理
原先的XmlHttpRequest
对象仅仅只有一个事件——onreadystatechange
,用以通知所有的事件,而现在,我们除了这个事件之外又多了很多新的。
onloadstart* | 当请求发生时触发 |
onprogress | 读取及发送数据时触发 |
onabort* | 当请求被中止时触发,如使用abort()方法 |
onerror | 当请求失败时触发 |
onload | 当请求成功时触发 |
ontimeout | 当调用者设定的超时时间已过而仍未成功时触发 |
onloadend* | 请求结束时触发(无论成功与否) |
注:带星号的表示IE的XDomainRequest
仍不支持。
数据来自http://www.w3.org/TR/XMLHttpRequest2/#events。
绝大多数情况下,我们只需要和onload
及onerror
打交道,就像下面这样:
xhr.onload = function() { var responseText = xhr.responseText; console.log(responseText); // 继续其它代码 }; xhr.onerror = function() { console.log('There was an error!'); };这儿有一点小异样。尽管我们可以通过
onerror
得知请求发生了错误,但在事件处理时,我们无法从代码上获知失败的任何原因。比如,FireFox在失败时将responseText
置空并返回一个0值作为状态,这当中并不包含任何错误的具体情况。
withCredentials
标准的CORS请求不对cookies做任何事情,既不发送也不改变。如果希望改变这一情况,就需要将withCredentials
设置为true
。
xhr.withCredentials = true;另外,服务端在处理这一请求时,也需要将
Access-Control-Allow-Credentials
设置为true
。这一点我们稍后来说。
withCredentials
属性使得请求包含了远程域的所有cookies,但值得注意的是,这些cookies仍旧遵守“同域”的准则,因此从代码上你并不能从document.cookies
或者回应HTTP头当中进行读取。
发送请求
请求通过一个简单的send()
方法进行发送,如果请求当中需要包含任何内容,也只需要将其作为一个参数传递给send()
即可。一旦服务端配置OK,那么你将只需要处理后续的onload
事件,这正像我们平时所熟悉的XHR一样。
来看一段完整的小代码:
// 创建XHR对象 function createCORSRequest(method, url) { var xhr = new XMLHttpRequest(); if ("withCredentials" in xhr) { // 针对Chrome/Safari/Firefox. xhr.open(method, url, true); } else if (typeof XDomainRequest != "undefined") { // 针对IE xhr = new XDomainRequest(); xhr.open(method, url); } else { // 不支持CORS xhr = null; } return xhr; } // 辅助函数,用于解析返回的内容 function getTitle(text) { return text.match('<title>(.*)?</title>')[1]; } // 发送CORS请求 function makeCorsRequest() { // bibliographica.org是支持CORS的 var url = 'http://bibliographica.org/'; var xhr = createCORSRequest('GET', url); if (!xhr) { alert('CORS not supported'); return; } // 回应处理 xhr.onload = function() { var text = xhr.responseText; var title = getTitle(text); alert('Response from CORS request to ' + url + ': ' + title); }; xhr.onerror = function() { alert('Woops, there was an error making the request.'); }; xhr.send(); }
服务端
一个CORS请求可能包含多个HTTP头,甚至有多个请求实际发送,这对于客户端的开发者来说通常是透明的。因为浏览器已经负责实现了CORS最关键的部分;但是服务端的后台脚本则需要我们自己进行处理,因此我们还需要了解到服务端到底从浏览器那里收到了怎样的内容。
先来看看流程图吧。
CORS分类
CORS可以分成两种:
- 简单请求
- 复杂请求
一个简单的请求大致如下:
- HTTP方法是下列之一
HEAD
GET
POST
- HTTP头包含
Accept
Accept-Language
Content-Language
Last-Event-ID
-
Content-Type
,但仅能是下列之一application/x-www-form-urlencoded
multipart/form-data
text/plain
任何一个不满足上述要求的请求,即被认为是复杂请求。一个复杂请求不仅有包含通信内容的请求,同时也包含预请求(preflight request)。
简单请求
为了搞清楚复杂请求与简单请求有何区别,我们首先来看看简单请求是怎样处理的。
JavaScript:
var url = 'http://alice.com/cors'; var xhr = createCORSRequest('GET', url); xhr.send();
HTTP请求:
GET /cors HTTP/1.1 Origin: http://api.alice.com Host: api.bob.com Accept-Language: en-US Connection: keep-alive User-Agent: Mozilla/5.0...简单请求的发送从代码上来看和普通的XHR没太大区别,但是HTTP头当中要求总是包含一个域(Origin)的信息。该域包含协议名、地址以及一个可选的端口。不过这一项实际上由浏览器代为发送,并不是开发者代码可以触及到的。
HTTP回应:
Access-Control-Allow-Origin: http://api.bob.com Access-Control-Allow-Credentials: true Access-Control-Expose-Headers: FooBar Content-Type: text/html; charset=utf-8在回应中,COR相关的项目全都是以“
Access-Control-
”作为前缀的,其意义分列如下:
-
Access-Control-Allow-Origin
(必含)- 不可省略,否则请求按失败处理。该项控制数据的可见范围,如果希望数据对任何人都可见,可以填写“*”。 -
Access-Control-Allow-Credentials
(可选) – 该项标志着请求当中是否包含cookies信息,只有一个可选值:true
(必为小写)。如果不包含cookies,请略去该项,而不是填写false
。这一项与XmlHttpRequest2
对象当中的withCredentials
属性应保持一致,即withCredentials
为true
时该项也为true
;withCredentials
为false
时,省略该项不写。反之则导致请求失败。 -
Access-Control-Expose-Headers
(可选) – 该项确定XmlHttpRequest2
对象当中getResponseHeader()
方法所能获得的额外信息。通常情况下,getResponseHeader()
方法只能获得如下的信息:Cache-Control
Content-Language
Content-Type
Expires
Last-Modified
Pragma
当你需要访问额外的信息时,就需要在这一项当中填写并以逗号进行分隔。不过目前浏览器对这一项的实现仍然有一些问题,具体请见文尾的BUG一节。
复杂请求
如果仅仅是简单请求,那么即便不用CORS也没有什么大不了,但CORS的复杂请求就令CORS显得更加有用了。简单来说,任何不满足上述简单请求要求的请求,都属于复杂请求。比如说你需要发送PUT
、DELETE
等HTTP动作,或者发送Content-Type: application/json
的内容。
复杂请求表面上看起来和简单请求使用上差不多,但实际上浏览器发送了不止一个请求。其中最先发送的是一种“预请求”,此时作为服务端,也需要返回“预回应”作为响应。预请求实际上是对服务端的一种权限请求,只有当预请求成功返回,实际请求才开始执行。
JavaScript:
var url = 'http://alice.com/cors'; var xhr = createCORSRequest('PUT', url); xhr.setRequestHeader( 'X-Custom-Header', 'value'); xhr.send();
预请求:
OPTIONS /cors HTTP/1.1 Origin: http://api.alice.com Access-Control-Request-Method: PUT Access-Control-Request-Headers: X-Custom-Header Host: api.bob.com Accept-Language: en-US Connection: keep-alive User-Agent: Mozilla/5.0...预请求以
OPTIONS
形式发送,当中同样包含域,并且还包含了两项CORS特有的内容:
-
Access-Control-Request-Method
– 该项内容是实际请求的种类,可以是GET、POST之类的简单请求,也可以是PUT
、DELETE
等等。 -
Access-Control-Request-Headers
– 该项是一个以逗号分隔的列表,当中是复杂请求所使用的头部。
显而易见,这个预请求实际上就是在为之后的实际请求发送一个权限请求,在预回应返回的内容当中,服务端应当对这两项进行回复,以让浏览器确定请求是否能够成功完成。例如,刚才的预请求可能获得服务端如下的回应:
Access-Control-Allow-Origin: http://api.bob.com Access-Control-Allow-Methods: GET, POST, PUT Access-Control-Allow-Headers: X-Custom-Header Content-Type: text/html; charset=utf-8来看看预回应当中可能的项目:
-
Access-Control-Allow-Origin
(必含) – 和简单请求一样的,必须包含一个域。 -
Access-Control-Allow-Methods
(必含) – 这是对预请求当中Access-Control-Request-Method
的回复,这一回复将是一个以逗号分隔的列表。尽管客户端或许只请求某一方法,但服务端仍然可以返回所有允许的方法,以便客户端将其缓存。 -
Access-Control-Allow-Headers
(当预请求中包含Access-Control-Request-Headers
时必须包含) – 这是对预请求当中Access-Control-Request-Headers
的回复,和上面一样是以逗号分隔的列表,可以返回所有支持的头部。 -
Access-Control-Allow-Credentials
(可选) – 和简单请求当中作用相同。 -
Access-Control-Max-Age
(可选) – 以秒为单位的缓存时间。预请求的的发送并非免费午餐,允许时应当尽可能缓存。
一旦预回应如期而至,所请求的权限也都已满足,则实际请求开始发送。
实际请求:
PUT /cors HTTP/1.1 Origin: http://api.alice.com Host: api.bob.com X-Custom-Header: value Accept-Language: en-US Connection: keep-alive User-Agent: Mozilla/5.0...
实际回应:
Access-Control-Allow-Origin: http://api.bob.com Content-Type: text/html; charset=utf-8
如果预请求所要求的权限服务端不允许,那么服务端可以直接返回一个普通的HTTP回应,比如:
// ERROR - No CORS headers, this is an invalid request! Content-Type: text/html; charset=utf-8
这样的返回因为不符合客户端的需求,因而客户端会直接将请求以失败计,虽然不是很美气,不过正符合我们的实际。此时如果客户端的onerror
事件有监听函数,那么将会触发,而浏览器的console窗口也会输出:
XMLHttpRequest cannot load http://api.alice.com. Origin http://api.bob.com is not allowed by Access-Control-Allow-Origin.不过很可惜,浏览器并不会给出详细的错误情况,仅仅是告知我们出错而已。
安全问题
跨域请求始终是网页安全中一个比较头疼的问题,CORS提供了一种跨域请求方案,但没有为安全访问提供足够的保障机制,如果你需要信息的绝对安全,不要依赖CORS当中的权限制度,应当使用更多其它的措施来保障,比如OAuth2。
已知问题
CORS是W3C中一项较“新”的方案,以至于各大网页解析引擎还没有对其进行完美的实现。下面是截至2011年11月13日时的已知问题:
-
getAllResponseHeaders()
方法无法获取Access-Control-Expose-Headers
当中要求的信息。在Chrome/Safari当中,仅仅只有简单的头部能够读取,其他无法获取;在FireFox当中,无法获得任何信息。(FireFox Bugzilla/Webkit Bugzilla) - 在Safari当中,使用
GET
、POST
方法的复杂请求发送时没有发送预请求的环节。 -
onerror
触发时statusText
获取不到任何内容。 - Opera截至11.60仍旧不支持CORS,但在12当中会支持(Opera Core Concerns – CORS goes mainline)。
阅读更多
[转自:http://newhtml.net/using-cors/]
发表评论
-
循环数组的逻辑怎么写
2015-03-23 10:24 646应用场景这样的: var imgUrls = [ ... -
发布`代码生成器`
2014-11-17 00:45 583闲话不说,直接上地址 npm: https://www. ... -
MutationObserver
2014-10-27 15:29 1098MutationObserver MutationObse ... -
a simple mvvm library - bird
2014-10-09 18:26 730see here:https://github.com/i ... -
遍历dom tree是一件相当耗时的事情
2014-09-23 01:15 755遍历dom tree是一件相当耗时的事情,尤其是在遍历的同时 ... -
今天再讲下js里的继承
2014-09-18 00:27 697js的继承说简单也很简单,请看: function ... -
Text 类型
2014-09-05 18:52 845文本节点由Text类型表 ... -
JavaScript插入动态脚本
2014-09-05 18:47 640动态脚本指的是在页面加载时不存在,但将来的某一时刻通过修改该 ... -
innerHTML插入<style>元素
2014-09-05 18:37 1163通过innerHTML写入<style>元素没 ... -
CSS实现相对浏览器窗口定位彻底研究
2014-09-05 18:33 3719Web Developer / Designer 经常需要将 ... -
JavaScript插入动态样式
2014-09-05 18:07 610能够把CSS样式包含到HTML页面中的元素有两个。其中,& ... -
再理解jQuery;delete原型属性
2014-05-13 22:05 1862以前用jQuery的时候曾粗略看了它的源码,但却不求甚解。 ... -
javascript &&和||
2012-07-23 00:38 700一直以为 && 和 || ... -
undefined 和 void 0 的区别
2012-07-20 11:15 703在读backbone源码时看见这么一段代码: if ( ... -
Fiddler - 前端开发值得拥有
2012-07-16 14:41 829最近换了新工作,搬了新家,换了新室友,一切都在重新开始。 ... -
说说我的web前端之路,分享些前端的好书
2012-07-16 14:38 792WEB前端研发工程师,在国内算是一个朝阳职业,这个领域没 ... -
JavaScript实现 页面滚动图片加载
2012-07-16 14:29 687又到了这个月的博客时间了,原计划是打算在这个月做一个的功 ... -
JavaScript 操作 Cookie
2012-07-16 11:18 684从事web开发也有些日 ... -
Javascript定义类(class)的三种方法
2012-07-12 12:35 586程序员们做了很多探索,研究如何用Javascript模拟”类” ... -
服务端解决跨源共享
2012-06-21 10:18 4517跨源资源共享是web开发领域中一个非常有趣的话题,互联网 ...
相关推荐
Java利用cors实现跨域请求实例 跨域请求是指浏览器不能执行其他网站的脚本,这是由浏览器的同源策略造成的,是浏览器对JavaScript施加的安全限制。这种限制会导致Ajax请求无法跨域访问其他网站的资源。为解决这个...
【标题】"cors跨域Tomcat文件"涉及的是在Web开发中解决跨域问题的一种常见方法,即使用CORS(Cross-Origin Resource Sharing)机制在Apache Tomcat服务器上配置和实现。CORS是一种允许浏览器安全地从不同源加载资源...
标题 "通过nginx实现跨域请求" 涉及的核心知识点是网络编程中的跨域问题以及如何利用Nginx服务器作为代理来解决这个问题。Nginx是一个高性能的HTTP和反向代理服务器,它常用于配置和管理网站的访问规则,包括处理...
实现跨域ajax请求的方式有很多,其中一个是利用CORS,而这个方法关键是在服务器端进行配置。 本文仅对能够完成正常跨域ajax响应的,最基本的配置进行说明(深层次的配置我也不会)。 CORS将请求分为简单请求和非简单...
2. **预检请求(Preflight Request)**:如果请求不符合简单请求的条件,浏览器会先发送一个`OPTIONS`请求到服务器,询问是否允许跨域。服务器响应中除了`Access-Control-Allow-Origin`,还需要包含`Access-Control-...
【Ajax跨域请求WebService.asmx】是一个常见的Web开发技术应用场景,主要涉及到JavaScript的Ajax技术、C#编程语言以及ASP.NET的WebService组件。Ajax(Asynchronous JavaScript and XML)是一种在不刷新整个页面的...
因此,应谨慎设置允许的源、方法和请求头,避免攻击者利用CORS获取敏感数据。 7. **问题排查**:当CORS设置出现问题时,浏览器的开发者工具网络面板可以查看到详细的请求和响应头,帮助定位问题。 总的来说,...
AJAX本身不支持跨域,但是通过CORS(Cross-Origin Resource Sharing,跨源资源共享)机制,可以实现AJAX的跨域请求。服务器需要在响应头中添加`Access-Control-Allow-Origin`字段,允许指定的源进行跨域请求。...
对于不符合简单请求标准的请求,浏览器会首先发送一个预检请求(`OPTIONS`)来确认服务器是否允许该跨域请求。预检请求成功后才会发送实际请求。 预检请求包含以下关键头部信息: - `Access-Control-Request-Method`...
除了JSONP,还可以通过CORS(Cross-Origin Resource Sharing,跨源资源共享)来实现跨域请求。CORS需要服务端支持,在响应头中添加`Access-Control-Allow-Origin`字段,指定允许哪些源进行跨域请求。在jQuery中,...
CORS是一种安全机制,通过在服务器端添加特定头部信息,使得浏览器允许跨域请求。这个dll文件包含了处理和响应跨域请求所需的功能。 配置ASP.NET WebApi支持跨域请求主要涉及以下步骤: 1. 引入 CORS 库:首先,...
**AJAX和JSONP跨域请求的实现过程** 1. **AJAX跨域**: 通常,AJAX请求受到同源策略限制。为实现跨域,我们可以使用CORS(Cross-Origin Resource Sharing)机制。服务器需要在响应头中添加`Access-Control-Allow-...
它利用了HTML中`<script>`标签不受同源策略限制的特点,通过动态创建`<script>`标签,将请求的URL设置为一个回调函数名加上服务器返回的数据,从而实现跨域数据交互。JSONP的核心在于服务器端需要支持动态返回...
另外,还可以使用JSONP(JSON with Padding)来实现跨域请求,它巧妙地利用了浏览器允许加载同一域名下的标签的特性。JSONP的工作原理是,服务器提供一个动态生成的JavaScript文件,其中包含一个回调函数,将数据...
3. 代理服务器:当目标服务器不支持CORS或JSONP时,可以在服务器端架设一个代理服务器,将跨域请求转发到目标服务器,再将结果返回给客户端。这种方式可以避免修改目标服务器的代码。 4. 使用WebSocket:WebSocket...
在提供的压缩包中,`TestAjax`可能是包含实现JSONP和CORS跨域请求的示例代码文件。这个文件可能包含了创建XMLHttpRequest对象、设置请求头、处理响应等内容的JavaScript代码,用于演示如何在实际项目中应用这些跨域...
- **JSONP**(JSON with Padding)是一种利用`<script>`标签不受同源策略限制的特点来实现跨域请求的技术。 - JSONP的实现原理是动态插入`<script>`标签,并将回调函数名作为参数传递给服务器,服务器返回的结果会在...
### AJAX跨域请求详解 #### 一、引言 在Web开发中,由于浏览器的同源策略限制,AJAX请求通常只能向同源服务器发送请求。...随着CORS(跨源资源共享)标准的普及,未来跨域请求的实现方式将会更加安全高效。
然而,为了解决这个问题,开发者可以利用CORS机制,通过在服务器端设置相应的响应头来放宽同源策略。 首先,我们需要理解CORS的工作原理。CORS通过在HTTP响应头中添加`Access-Control-Allow-Origin`字段来指定哪些...