> 几个问题:
1. 什么是跨域?
2. 为什么会有跨域?
3. 如何处理跨域
我们在日常的开发中,经常会遇到跨域资源共享,或者进行跨域接口访问的情况。跨域资源共享( CORS)机制允许 Web 应用服务器进行跨域访问控制。
跨域资源共享标准新增了一组 HTTP 首部字段,允许服务器声明哪些源站通过浏览器有权限访问哪些资源。另外,规范要求,对那些可能对服务器数据产生副作用的 HTTP 请求方法(特别是GET
以外的 HTTP 请求,或者搭配某些 MIME 类型的POST
请求),浏览器必须首先使用OPTIONS
方法发起一个预检请求(preflight request),从而获知服务端是否允许该跨域请求。服务器确认允许之后,才发起实际的 HTTP 请求。在预检请求的返回中,服务器端也可以通知客户端,是否需要携带身份凭证(包括Cookies和 HTTP 认证相关数据)。
在涉及到CORS的请求中,我们会把请求分为简单请求和复杂请求。
简单请求
满足以下条件的请求即为简单请求:
- 请求方法:GET、POST、HEAD
-
除了以下的请求头字段之外,没有自定义的请求头
- Accept
- Accept-Language
- Content-Language
- Content-Type
- DPR
- Downlink
- Save-Data
- Viewport-Width
- Width
-
Content-Type的值只有以下三种
(Content-Type一般是指在post请求中,get请求中设置没有实际意义)
- text/plain
- multipart/form-data
- application/x-www-form-urlencoded
-
请求中的任意XMLHttpRequestUpload 对象均没有注册任何事件监听器
(未验证)
- XMLHttpRequestUpload 对象可以使用 XMLHttpRequest.upload 属性访问
- 请求中没有使用 ReadableStream 对象
(未验证)
复杂请求
非简单请求即为复杂请求。复杂请求我们也可以称之为在实际进行请求之前,需要发起预检请求的请求。
简单请求
与复杂请求
的跨域设置
针对简单请求,在进行CORS设置的时候,我们只需要设置
Access-Control-Allow-Origin:*
// 如果只是针对某一个请求源进行设置的话,可以设置为具体的值
Access-Control-Allow-Origin: 'http://www.yourwebsite.com'
针对复杂请求,我们需要设置不同的响应头。因为在预检请求的时候会携带相应的请求头信息
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-CUSTOMER-HEADER, Content-Type
相应的响应头信息为:
Access-Control-Allow-Origin: http://foo.example
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
// 设置max age,浏览器端会进行缓存。没有过期之前真对同一个请求只会发送一次预检请求
Access-Control-Max-Age: 86400
如果发送的预检请求被进行了重定向,那大多数的浏览器都不支持对预检请求的重定向。我们可以通过先发送一个简单请求的方式,获取到重定向的url XHR.responseURL,然后再去请求这个url。
附带身份凭证的请求
一般而言,对于跨域 XMLHttpRequest
或 Fetch 请求,浏览器不会发送身份凭证信息。如果要发送凭证信息,需要设置 XMLHttpRequest 的某个特殊标志位。
如果在发送请求的时候,给xhr 设置了withCredentials为true,从而向服务器发送 Cookies,如果服务端需要想客户端也发送cookie的情况,需要服务器端也返回Access-Control-Allow-Credentials: true
响应头信息。
对于附带身份凭证的请求,服务器不得设置 Access-Control-Allow-Origin
的值为“*
”。
这是因为请求的首部中携带了Cookie
信息,如果 Access-Control-Allow-Origin
的值为“*
”,请求将会失败。而将 Access-Control-Allow-Origin
的值设置为 http://foo.example
(请求源),则请求将成功执行。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。