C O R S

所有前端工程师都知道跨域问题(不同的协议、域、端口),也都知道解决跨域的常见方式是通过设置cors。 那么cors到底是什么,它是如何解决跨域问题的呢

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

简单请求和非简单请求

满足以下条件即视为简单请求

  • 请求方法为以下任意方法之一(在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面板看到类似于下面这样报错

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请求,包含以下字段

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

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

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.

另外,需要同时对接口的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


HaHa
525 声望11 粉丝