本文为译文。

简介

APIS是可以将富网页应用串连在一起的线程。但是这个应用难以转给浏览器,跨域请求技术的选择被限制了,类似JSONP(由于安全考虑,使用会被限制),或者配置代理(设置和维护都比较头痛)。

Cross-Origin Resource Sharing(CORS)是允许来自浏览器的跨域通信的W3C规范。通过设置XMLHttpRequest的头部,CORS允许开发者使用类似同域中请求惯用的方法。

CORS的用法很简单,假设网站alice.com有一些bob.com想要获取的数据。这类型的请求以前通常在浏览器的同源策略下不被允许。但是,借助CORS请求,alice.com可以加一些特殊回应头信息允许bob.com取得数据。

可以从这个例子里面看出来,支持CORS需要服务器和客户端之间的协调。幸运的是,如果你是客户端开发者,你可以屏蔽掉这中间大多数的细节。这篇文章余下的部分会展示客户端如何进行跨域请求,及服务器如何配置来支持CORS。

发起CORS请求

这部分介绍如何使用javascript发起CORS请求。

创建XMLHttpRequest请求:

下列浏览器支持CORS:

Chrome 3+

Firefox 3.5+

Opera 12+

Safari 4+

Internet Explorer 8+

Chrome,Firefox,Opera,Safari都使用XMLHttpRequest2对象,IE使用类似的XDomainRequest对象,与他本身对应的XMLHttpRequest对象工作机制基本相同,但是另外增加了安全防范。

首先要创建合适的请求对象,像这样:

事件处理

原始的XMLHttpRequest只有一个事件处理onreadystatechange,来处理所有的响应。虽然onreadystatechange依然可以使用,XMLHttpRequest2引进了一系列新的处理,下面是一个列表:

在大多数情况下,你只仅仅想处理onload和onerror事件:

当有错误的时候,浏览器不会报告是什么错误。例如,FF对所有错误报告一个状态0和空statusText。浏览器也会向控制输出台报错,但是这个消息没法被javascript获取到。当处理onerror的时候,会知道有一个错误发生了,但没有更多信息了。

withCredentials

标准的CORS在默认情况下不发送和设置任何cookie。为了使cookie成为请求的一部分包含进来,需要设置XMLHttpRequest的withCredentials属性为true:

为了达成这个目的,服务器也需要设置Access-Control-Allow-Credientials为true来允许认证。

withCredentials属性会包含来自远程域的请求的任何cookie。注意这些cookies仍然遵循同源策略,所以你的javascript代码仍然从document.cookie中访问不到这些cookies或者请求头.他们只能被远程域所控制。

发送请求

现在你的CORS请求已经配置好了,你准备发送请求。这个通过调用send()方法来实现:

如果请求包含请求体,可以被指定为一个参数给send().

就是酱紫!假定服务器已经完全配置好来响应CORS请求了,你的onload处理会收到响应,就像你十分熟悉的标准的同域XHR那样。

最后最后一个例子

这是一个完整的CORS请求例子。运行下例子在浏览器debugger里面看看发送的请求。

在服务器端添加CORS支持

多数的CORS重担在浏览器和服务器之间被处理了。浏览器增加了额外的一些头,有时发起额外的请求,在CORS请求期间。这些额外的请求对于客户端是不可见的(可以使用Wireshark等工具来捕获)。

浏览器厂商对于浏览器端的实现是有责任的。下面了解下服务器端如何配置来支持CORS。

请求的类型

跨域请求分类:

1.简单请求

2.非简单请求

简单请求不需要使用CORS从浏览器发出请求。例如,一个JSONP跨域请求可以是一个跨域的GET请求。

非简单请求,在浏览器与服务器间需要一点额外的交互。

处理一个简单请求

以一个客户端的简单请求为例。下面代码展示了javascript的一个GET请求,以及浏览器发送的实际请求。CORS中特殊的头粗体显示。

首先需要注意的是,一个合法的CORS请求总是包含Origin头。这个Origin头是浏览器加上去的,并且不能被用户控制。这个头的值是来自请求源的协议(例如http),域(例如bob.com),和端口(只在不是默认端口的情况下包含,例如81);例如http://api.alice.com.

Origin头的存在不意味着请求是一个跨域请求。虽然所有跨域的请求都会包含Origin头,一些同域请求同样也会包含Origin头。例如,火狐在同域请求中不包含Origin头。但是Chrome和Safari在同域的POST/PUT/DELETE请求(同域的GET请求不会有Origin头)中会包含Origin头。下面有一个同域请求包含Origin头的例子:

值得庆幸的是浏览器在同域请求时不会期望CORS请求头。同域请求的响应发送给用户,不管是否有CORS请求头。然而,如果服务器代码返回了如果Origin不匹配允许的域列表的错误,确保包含请求的来源域。

所有CORS相关的的头都是Access-Control为前缀的。下面是每个头的一些细节。

Access-Control-Allow-Origin(必须)-这个头在所有合法的CORS响应中必须被包含;发送头会引起CORS请求失败。这个头的值可以是Origin请求头的回应(就像上面的例子里面一样),或者是允许来自任何域请求的"*"。如果你希望任何站点都可以获取数据,使用"*"就很好。但是如果你希望更好的控制谁可以获取你的数据,在头中使用一个实际的值。

Access-Control-Allow-Credentials(可选)-默认情况下,cookies在CORS请求中不被包含。使用这个头意味着在CORS请求中应当包含cookies.这个头的唯一合法值是true(全部小写)。如果不需要cookies,不要包含这个头(而不是把值设置为false).

Access-Control-Allow-Credentials头与XMLHttpRequest2的withCredentials属性结合使用。所有这些属性都必须设置为true以便于CORS请求能够成功。如果withCredentials是true,但是没有Access-Control-Allow-Credentials头,请求会失败(反之亦然)。

上面提到过,除非你确定需要cookies包含在请求中,否则不设置这个头。

Access-Control-Expose-Headers(可选)-XMLHttpRequest2对象有一个返回特别响应头值的getResponseHeader()方法。在CORS请求中,getResponseHeader()只能获取简单的响应头。简单响应头定义如下:

如果希望客户端获取其他头,必须用Access-Control-Expose-Headers头。这个头的值是一个逗号分隔的想要公开给客户端的响应头列表。

处理非简单请求

上面就是如何处理简单GET请求,但如果想要做更多的事情要怎么做?也许你想要支持其他HTTP动作,像PUT或DELETE,或者想要使用Content-Type:application/json支持JSON.你就需要处理所谓非简单请求。

非简单请求看上去像到客户端的一个单一请求,但是实际上在遮罩下包含了两个请求。浏览器首先发出一个预先请求,就好像询问服务器应允进行实际请求。一旦被允许,浏览器发送实际请求。浏览器透明的处理这两个请求的细节。预响应也可以被缓存下来以便不需要在每个请求前都发送。

下面是一个非简单请求的例子:

像简单请求一样,浏览器给每个请求加上Origin头,包含预请求。预请求像HTTP OPTIONS请求一样发出(所以确保服务器可以响应这个方法).他也包含额外的一些头:

Access-Control-Request-Method-HTTP实际请求的方法。这个请求头总是被包含,即使HTTP请求是一个简单请求,就像早些定义的那些(GET,POST,HEAD).

Access-Control-Request-Headers-一个在请求中包含的非简单头的逗号分隔的列表。

预请求是在发送实际请求前,问询服务器是否允许实际请求的方式。服务器应当检查上面的两个头来确认HTTP方法和请求头是合法的及可以接受的。

如果HTTP请求方法和头是合法的,服务器会如下响应:

Access-Control-Allow-Origin(必须)-如简单响应一样,预响应必须包含这个头。

Access-Control-Allow-Method(必须)-所支持的HTTP方法逗号分隔的列表。注意虽然预请求只是询问HTTP方法是否允许,响应头可以包含所有支持的HTTP方法。这个是有帮助的,因为预响应可能会被缓存,所以单一的预响应可以包含多种请求类型的细节。

Access-Control-Allow-Headers(如果请求头包含Access-Control-Allow-Headers就必须包含)-逗号分隔的所支持的请求头列表。像上面的Access-Control-Allow-Methods一样,这个可以列出服务器支持的所有头(不仅仅是在预请求中请求的头)。

Access-Control-Allow-Credentials(可选)-同简单请求。

Access-Control-Max-Age(可选)-在每个请求上进行预请求是代价很高的,因为浏览器对于客户端的请求会进行两次请求。这个头的值允许预响应缓存一个指定的秒数。

一旦预请求给到了应允,浏览器发送实际请求。实际请求看起来像简单请求,响应以同样的方式处理:

如果服务器想否决CORS请求,可以只返回一个通用的响应(像HTTP 200),不带任何CORS请求头。如果预请求时的HTTP方法或者头不合法,服务器可能想要否决请求。由于在响应中没有CORS特定的头,浏览器断定请求是不合法的,不发送实际请求:

如果在CORS请求中有错误,浏览器会触发客户端的onerror事件处理。也会在控制台上打印下面的错误:

浏览器不会给为什么错误会发生的细节信息,只告诉你出了些问题。

关于安全

虽然CORS奠定了跨域请求的基础工作,CORS头不是健全的安全实践的替代。在站点上不能够依赖CORS头保护资源安全。使用CORS头给予浏览器跨域请求的接入,但是使用其他的安全手段,像cookies或者OAuth2,如果需要额外的安全限制的话。

来自jQuery的CORS

jQuery的$.ajax()方法可以用来进行常规XHR请求和CORS请求。一点点jQuery相关实现的笔记:

  • jQuery的CORS实现不包含IE的XDomainRequest对象。但是有jQuery插件可以用这个。可以在http://bugs.jquery.com/ticket/8283上查看细节。
  • 如果浏览器支持CORS的话(在IE中会返回false,看下上条说明),$.support.cors布尔量会被设置成true。这是检查是否支持CORS的快速方法。

下面是一个用jQuery进行CORS请求的例子。注释给出了确切的属性如何与CORS交互。

Chrome扩展件的跨域

Chrome扩展件以两种不同的方式支持跨域:

  1. 在manifest.json中包含域-Chrome扩展件可以向任何域发送跨域请求,如果域被包含在manifest.json文件的permissions部分:服务器不需要包含任何额外的CORS头或者做另外的工作来使请求成功。
  2. CORS请求-如果域不在manifest.json文件中,Chrome扩展件进行一个标准的CORS请求。Origin头的值是"chrome-extension://[CHROME EXTENSION ID]".这意味着来自Chrome扩展件的请求受本文提到的同样的CORS请求规则的约束。

CORS w/图片

在Canvas和WebGL上下文中,跨域图片可以造成很大的问题。可以在img元素上使用crossOrigin属性。

CORS服务器流程图

下面的流程图说明了服务器如何确定在CORS响应中需要加哪些头。

--end--

相关文章:https://docs.webplatform.org/wiki/tutorials/using_cors

使用CORS:跨域两三事的更多相关文章

  1. 如何在ASP.NET Core中实现CORS跨域

    注:下载本文的完整代码示例请访问 > How to enable CORS(Cross-origin resource sharing) in ASP.NET Core 如何在ASP.NET C ...

  2. ajax——CORS跨域调用REST API 的常见问题以及前后端的设置

    RESTful架构是目前比较流行的一种互联网软件架构,在此架构之下的浏览器前端和手机端能共用后端接口. 但是涉及到js跨域调用接口总是很头疼,下边就跟着chrome的报错信息一起来解决一下. 假设:前 ...

  3. Web APi之手动实现JSONP或安装配置Cors跨域(七)

    前言 照理来说本节也应该讲Web API原理,目前已经探讨完了比较底层的Web API消息处理管道以及Web Host寄宿管道,接下来应该要触及控制器.Action方法,以及过滤器.模型绑定等等,想想 ...

  4. Web API 实现JSONP或者安装配置Cors跨域

    前言 照理来说本节也应该讲Web API原理,目前已经探讨完了比较底层的Web API消息处理管道以及Web Host寄宿管道,接下来应该要触及控制器.Action方法,以及过滤器.模型绑定等等,想想 ...

  5. CORS 跨域 实现思路及相关解决方案

    本篇包括以下内容: CORS 定义 CORS 对比 JSONP CORS,BROWSER支持情况 主要用途 Ajax请求跨域资源的异常 CORS 实现思路 安全说明 CORS 几种解决方案 自定义CO ...

  6. 解决ajax请求cors跨域问题

    ”已阻止跨源请求:同源策略禁止读取位于 ***** 的远程资源.(原因:CORS 头缺少 'Access-Control-Allow-Origin').“ ”已阻止跨源请求:同源策略禁止读取位于 ** ...

  7. Asp.Net WebApi 启用CORS跨域访问指定多个域名

    1.后台action指定 EnableCors指定可访问的域名多个,使用逗号隔开 //支持客户端凭据提交,指定多个域名,使用逗号隔开 [EnableCors("http://localhos ...

  8. Cors 跨域Access-Control-Allow-Origin

    1.Access-Control-Allow-Origin 指定格式 The Origin header field has the following syntax: origin = " ...

  9. Asp.Net WebApi+Microsoft.AspNet.WebApi.Core 启用CORS跨域访问

    WebApi中启用CORS跨域访问 1.安装 Nugget包Microsoft.AspNet.WebApi.Cors This package contains the components to e ...

  10. jsonp与cors跨域的一些理解

    浏览器的同源策略,即是浏览器之间要隔离不同域的内容,禁止互相操作. 比如,当你打开了多个网站,如果允许多个网站之间互相操作,那么其中一个木马网站就可以通过这种互相操作进行一系列的非法行为,获取你在各个 ...

随机推荐

  1. win7下vs2008编译出现C1859错误的处理办法

    昨天,电脑上安装的vs2008 sp1版本编译工程时候出了这样的错了:fatal error C1859: 'Debug\**.pch'.清理并重新编译会临时解决问题,但问题仍然会频发.后面上网找资料 ...

  2. 论文他引次数及ESI高被引论文查询方法

    https://yunpan.cn/cS67Z9UEDvc2b 访问密码 f078

  3. Win8下修改任務欄的資源管理器默認打開位置

    不能像win7一樣右鍵屬性改了,但還是有辦法的. 新建一個文件夾,建立快捷方式,右鍵快捷方式,將目標改為%windir%\explorer.exe /n,/e,D:\Desktop 然後將該快捷方式拖 ...

  4. HTTP 错误 500.19 - Internal Server Error

    ylbtech-Error-IIS: HTTP 错误 500.19 - Internal Server Error 1.A,错误代码返回顶部 错误摘要 HTTP 错误 500.19 - Interna ...

  5. Java Volatile相关文章目录

    参考资料: http://www.google.com/cse?sa.x=0&sa.y=0&cx=010284515138798138769%3Aajbqkpwaapm&ie= ...

  6. Git中的文件状态和使用

    (暂存区 即Index In Git) commit 到 local respository的内容,不想push,则使用git reset 将文件状态回转到staged|modified|unstag ...

  7. 关于ie6下拖动滚动条时,div抖动的问题解决

    你如果遇到了这个问题,算是你有福了. 首先说非ie6下的div不随滚动条变化而移动位置的. 1,首先在body中写足够多的文字,一直到浏览器出现滚动条.例如你可以拼命的放P,足够多的P标签 2建立一个 ...

  8. C Primer Plus(第五版)7

    第 7 章 C 控制语句:分支和跳转 在本章中你将学习下列内容: · 关键字:if(如果),else(否则),switch(切换),continue(继续),break(中断), case(情况),d ...

  9. @Valid springMVC bean校验不起作用

    @RequestMapping("/add2") public String addStudentValid(@Valid @ModelAttribute("s" ...

  10. hive 调用java的函数和科学记数法转换

    hive中field如果是string,比如id,那么使用10000000000+id结果是科学计数法显示,转换为正常显示方法: select (10000000000+cast(id as int) ...