C O R S简述

C O R S

全部前端工程师都知道跨域问题(不一样的协议、域、端口),也都知道解决跨域的常见方式是经过设置cors。 那么cors究竟是什么,它是如何解决跨域问题的呢前端

CORS全称Cross-Origin Resource Sharing,即跨域资源共享。是解决跨域问题常见的方式。api

简单请求和非简单请求

知足如下条件即视为简单请求跨域

  • 请求方法为如下任意方法之一(在W3C规范中也称为简单方法 simple method浏览器

    • GET
    • HEAD
    • POST
  • 请求头只能包含如下字段 (在W3C规范中前4种称为简单头部 simple header,不包括浏览器自动设置的那些,好比User-Agent,Connection等)缓存

    • Accept
    • Accept-Language
    • Content-Language
    • Content-Type (仅支持 application/x-www-form-urlencoded 、multipart/form-data 、text/plain)
    • DPR
    • Downlink
    • Save-Data
    • Viewport-Width
    • Width
  • 请求中的XMLHttpRequestUpload对象没有注册事件监听
  • 请求中没有使用 ReadableStream 对象。

对于简单请求,浏览器会直接发起实际跨域请求,只要返回头部中设置了正确的Access-Control-Allow-Origin字段便可成功请求,不然你会在浏览器的console面板看到相似于下面这样报错cookie

Access to XMLHttpRequest at 'http://domain.com/api/test' from origin 'http://localhost:1234' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.前端工程师

对于非简单请求,在发起实际的请求以前,浏览器会发起一个预检请求(preflight request),这是个options请求,包含如下字段app

  • Access-Control-Request-Method (表示实际发生的请求方法)
  • Access-Control-Request-Headers (若是实际的请求头部不为空,则会将实际的请求头部中用到的字段放入该字段中)
  • Origin (表示请求来源)

当预检请求经过后,才会发起真实的请求,不然你会在浏览器的console面板看到相似于下面这样报错(这里是请求头没有经过预检)cors

Access to XMLHttpRequest at 'http://domain.com/api/test' from origin 'http://localhost:1234' has been blocked by CORS policy: Request header field custom-header is not allowed by Access-Control-Allow-Headers in preflight response.dom

另外,须要同时对接口的options方法以及真实的getpost方法设置对应的返回头。若是只设置了真实请求方法的返回头,而没有相应设置options方法的返回头,预检也不会经过。你会在浏览器的console面板看到相似于下面这样报错

Access to XMLHttpRequest at 'http://domain.com/api/test' from origin 'http://localhost:1234' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

并不是全部非简单方法都会发起预检请求

预检请求是有缓存的!在预检请求的返回头中设置Access-Control-Max-Age字段,值为int类型,表明过时时间,单位是秒。 在该时间段以内,非简单方法发送跨域请求不会再事先发起预检请求。

response header

对于预检请求,能够返回下列字段

  • Access-Control-Allow-Origin (容许的域)
  • Access-Control-Allow-Method (容许的请求方法,简单请求可不列出,也就是说即便你只设置了POST,GET方法也是会经过的)
  • Access-Control-Allow-Headers (容许的请求头部)
  • Access-Control-Max-Age (缓存时间,上面已经介绍过了)
  • Access-Control-Allow-Credentials(是否容许携带用户认证信息 cookie , HTTP authentication等,当该值为true时,Access-Control-Allow-Origin不能为*,当该值为false,同时请求又携带了credentials,该请求的返回会被浏览器忽略)
  • Access-Control-Expose-Headers (能够暴露给浏览器的头部)

本文主要知识来源并推荐阅读:

MDN
W3C