Open Quickeryi opened 7 years ago
Cross-origin resource sharing 什么是CORS 全称跨域资源共享,它是W3C的一个标准,用来解决跨域问题! 它与JSONP有何不同 jsonp虽然说也是一个标准,但是它不是官方的,而是开发者们依靠自己的聪明才智创造出来的 jsonp只能用在GET请求中,这是一个很大的限制,而CORS可以使用所有的HTTP方法 如何使用CORS 要完美的使用CORS依赖于两部分:客户端(浏览器)& 服务端。首先浏览器必须支持CORS,目前来说只有IE10-不支持,同样服务端需要设置需要允许跨域请求并响应。 CORS请求分类 CORS的请求分为两种:简单请求(simple request)和非简单请求(not-so-simple request)
Cross-origin resource sharing
全称跨域资源共享,它是W3C的一个标准,用来解决跨域问题!
jsonp
GET
CORS
HTTP
要完美的使用CORS依赖于两部分:客户端(浏览器)& 服务端。首先浏览器必须支持CORS,目前来说只有IE10-不支持,同样服务端需要设置需要允许跨域请求并响应。
IE10-
CORS的请求分为两种:简单请求(simple request)和非简单请求(not-so-simple request)
整个CORS通信过程,都是浏览器自动完成,不需要开发者在客户端特别设置什么。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息
一般来说我们使用CORS时都是触发简单请求,满足以下条件的就是简单请求:
1. 请求方法是以下三种之一: 1)HEAD 2)GET 3)POST - 仅当POST方法的Content-Type值等于下列之一 1)text/plain 2)multipart/form-data 3)application/x-www-form-urlencoded 2. 不得人为设置除下列集合以外的头部字段 1)Accept 2)Accept-Language 3)Content-Language 4)Content-Type (注意上述POST请求的限制) 5)DPR 6)Downlink 7)Save-Data 8)Viewport-Width 9)Width
对于简单请求,在Request Headers中会新增一个Origin字段,该字段就是指定请求源,如下图:
Request Headers
Origin
如果服务端没有对跨域做特殊处理,那么浏览器接收到响应后不会正确处理,而会报错,并且该错误可以被XMLHttpRequest.onerror捕获,如下图所示:
XMLHttpRequest.onerror
如何才能让浏览器正确响应 其实很简单,只需要在服务端响应时,设置一个额外的头部信息即可:
Access-Control-Allow-Origin: <origin> | *
除了上述 Access-Control-Allow-Origin 的响应头部字段外,还有一些其他的极其重要的字段
// client var xhr = new XMLHttpRequest(); xhr.withCredentials = true; // 设置 浏览器 发送CORS请求时带上cookie
// server res.header('Access-Control-Allow-Credentials', true)
**还需要注意两点:** 1)一旦 `server` 端设置了 `Access-Control-Allow-Credentials` 那么 `Access-Control-Allow-Origin `就不能设置通配符 `*`,否则会报错,如下所示: ![error](https://user-images.githubusercontent.com/25584184/30208144-bb8f3b78-94c4-11e7-8b9d-75c6d1e341f9.png) 2)一旦设置了 `xhr.withCredentials=true`,那么必须设置`Access-Control-Allow-Credentials: true`否则会报错! - **Access-Control-Expose-Headers**:在`CORS`请求响应中,我们通过`xhr.getResponseHeader `只能拿到一些通用的头部,如果我们想要拿到一些自定义的头部信息,则需要设置`Access-Control-Expose-Headers`,如下所示: ```javascript // server res.set({ 'X-Customer-Header-1': '1', 'X-Customer-Header-2': '2', 'Access-Control-Expose-Headers': 'X-Customer-Header-1, X-Customer-Header-2' }) // client xhr.getResponseHeader('X-Customer-Header-1') // 1
非简单请求的说法并不是官方定义的,而是为了区分简单请求而已。
官方定义:跨域资源共享标准新增了一组 HTTP 首部字段,允许服务器声明哪些源站有权限访问哪些资源。另外,规范要求,对那些可能对服务器数据产生副作用的 HTTP 请求方法(特别是 GET 以外的 HTTP 请求,或者搭配某些 MIME 类型的 POST 请求),浏览器必须首先使用 OPTIONS 方法发起一个预检请求(preflight request),从而获知服务端是否允许该跨域请求。服务器确认允许之后,才发起实际的 HTTP 请求。在预检请求的返回中,服务器端也可以通知客户端,是否需要携带身份凭证(包括 Cookies 和 HTTP 认证相关数据)。
MIME
POST
OPTIONS
preflight request
Cookies
说明:从官方定义可以总结出来,非简单请求其实包括两部分(preflight request + 实际请求),使用一副图来形象的展示一下:
注意:预检请求对于用户来说是透明的,无感知的!
如何触发预检请求:这其实就回到了如何触发非简单请求的问题上来了,直接看上面如何触发简单的请求的条件即可,不满足则就会触发非简单请求。
深入头部信息:我们下面看看非简单请求的头部信息有何不一样呢
preflight
Access-Control-Request-Headers
Access-Control-Request-Method
下面说明一下非简单请求涉及到的特殊的头部信息
Access-Control-Allow-Headers
Access-Control-Allow-Methods
------------------ 未完,接着下面评论 --------------------
Access-Control-Max-Age:大家可能会想,我如果不想每次都发送preflight,而是只是在第一次请求时发送,而后将其缓存住,之后的每次请求都只发送实际请求即可。那么就需要用到这个响应头部,它用来指定preflight请求的结果能够被缓存多久。
Access-Control-Max-Age
讲到这里基本上把关于CORS的一些概念与实践论述清楚了,下面引用两张MDN的图来概括一下吧!
MDN
跨域资源共享 CORS 详解
HTTP访问控制(CORS)
本章谈谈CORS那些有意思的事
整个
CORS
通信过程,都是浏览器自动完成,不需要开发者在客户端特别设置什么。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息何为简单请求
一般来说我们使用
CORS
时都是触发简单请求,满足以下条件的就是简单请求:对于简单请求,在
Request Headers
中会新增一个Origin
字段,该字段就是指定请求源,如下图:如果服务端没有对跨域做特殊处理,那么浏览器接收到响应后不会正确处理,而会报错,并且该错误可以被
XMLHttpRequest.onerror
捕获,如下图所示:如何才能让浏览器正确响应 其实很简单,只需要在服务端响应时,设置一个额外的头部信息即可:
HTTP 响应头部字段
// server res.header('Access-Control-Allow-Credentials', true)
何为非简单请求
官方定义:跨域资源共享标准新增了一组
HTTP
首部字段,允许服务器声明哪些源站有权限访问哪些资源。另外,规范要求,对那些可能对服务器数据产生副作用的HTTP
请求方法(特别是GET
以外的HTTP
请求,或者搭配某些MIME
类型的POST
请求),浏览器必须首先使用OPTIONS
方法发起一个预检请求(preflight request
),从而获知服务端是否允许该跨域请求。服务器确认允许之后,才发起实际的HTTP
请求。在预检请求的返回中,服务器端也可以通知客户端,是否需要携带身份凭证(包括Cookies
和HTTP
认证相关数据)。说明:从官方定义可以总结出来,非简单请求其实包括两部分(
preflight request
+ 实际请求),使用一副图来形象的展示一下:注意:预检请求对于用户来说是透明的,无感知的!
如何触发预检请求:这其实就回到了如何触发非简单请求的问题上来了,直接看上面如何触发简单的请求的条件即可,不满足则就会触发非简单请求。
深入头部信息:我们下面看看非简单请求的头部信息有何不一样呢
OPTIONS
方法(当然,这不需要开发者关心,浏览器会做好一切),用来询问服务器是否允许之后的实际请求,如果不允许,则浏览器不会发送后面的实际请求。预检请求的头部信息如下图: 是的,可以看出preflight
有两个特殊的头部信息:Access-Control-Request-Headers
Access-Control-Request-Method
下面说明一下非简单请求涉及到的特殊的头部信息
Access-Control-Request-Method
:用于预检请求。其作用是,将实际请求所使用的HTTP
方法告诉服务器Access-Control-Request-Headers
:用于预检请求。其作用是,将实际请求所携带的首部字段告诉服务器Access-Control-Allow-Headers
:用于预检请求的响应。其指明了实际请求中允许携带的首部字段Access-Control-Allow-Methods
:用于预检请求的响应。其指明了实际请求所允许使用的 HTTP 方法------------------ 未完,接着下面评论 --------------------