这是我参与「第四届青训营」笔记创作活动的第4天
前言
众所周知,掘金社区中大部分同学都是处理前端工作的。不知道大家还记不记得第一次和后端对接时的场景?
我是记得的。当我按照后端的要求,把接口全都处理妥当之后——哎?特喵的怎么没有显示呢?赶紧打开开发者工具看一看,这一看不要紧,映入眼帘的全部是大红框框:
于是我气冲冲的去找了负责后端的同学,迎来的却是一盆冷水——
“我(后端)测试的好好的,怎么到你这儿来就不好用了呢?”
说完还打开Postman当场调给我看,我在自己机器上一试,哎,直接访问是可以的,怎么从浏览器里访问就出不去了呢?
后来才明白了,原来是跨域CORS问题没有处理好!
CORS简介
先来看看MDN上给出的CORS定义:
CORS (Cross-Origin Resource Sharing,跨域资源共享)是一个系统,它由一系列传输的HTTP 头组成,这些 HTTP 头决定浏览器是否阻止前端 JavaScript 代码获取跨域请求的响应。
我们来提取一下关键词:
由一系列HTTP头组成——说明跟被请求的资源返回来的header头有关(好家伙!不是我前端的问题,是后端/运维的问题!)决定是否阻止...响应——喔,这些header头可以决定我是不是可以访问- 获取
跨域请求的响应——等等,什么叫跨域请求?MDN上的例子简单粗暴,我们直接搬过来:运行在https://domain-a.com的 JavaScript 代码使用XMLHttpRequest来发起一个到https://domain-b.com/data.json的请求。
到这里是不是豁然开朗了?简单来说,就是后端返回请求中的某些header,可以决定前端是否可以跨域请求相应。
于是接下来的问题是:需要设置哪些header呢?
与CORS相关的header
注:以下定义摘自于MDN
Access-Control-Allow-Origin
Access-Control-Allow-Origin指定了该响应的资源是否被允许与给定的origin共享。
例如:
# 允许所有资源访问
Access-Control-Allow-Origin: *
# 允许指定资源访问
Access-Control-Allow-Origin: https://abc.com
Access-Control-Allow-Methods
Access-Control-Allow-Methods在对 preflight request.(预检请求)的应答中明确了客户端所要访问的资源允许使用的方法或方法列表。
例如:
# 允许通过POST / GET / OPTIONS方法访问
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Credentials
Access-Control-Allow-Credentials响应头用于在请求要求包含 credentials(Request.credentials 的值为 include)时,告知浏览器是否可以将对请求的响应暴露给前端 JavaScript 代码。
注:所谓的
credentials可以是 cookies、authorization headers 或 TLS client certificates。
例如:
# 允许将对请求的响应暴露给前端 JavaScript 代码
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers
Access-Control-Allow-Headers用于 preflight request(预检请求)中,列出了将会在正式请求的 Access-Control-Request-Headers 字段中出现的首部信息。
一句话:Access-Control-Allow-Headers规定了允许带上的其他header属性。
例如:
Access-Control-Allow-Headers: Authorization, Content-Type, Accept, Origin, User-Agent, DNT, Cache-Control, X-Mx-ReqToken, X-Data-Type, X-Requested-With, X-Data-Type, X-Auth-Token, token
预检请求
在上面的分析中,出现了一个词:预检请求。当我们请求一些复杂资源时,浏览器会自动发出一个“预检请求”,用于检查服务器是否支持 CORS 即跨域资源共享。
以下是来自MDN的一个例子:
一个客户端可能会在实际发送一个
DELETE请求之前,先向服务器发起一个预检请求,用于询问是否可以向服务器发起一个DELETE请求:OPTIONS /resource/foo Access-Control-Request-Method: DELETE Access-Control-Request-Headers: origin, x-requested-with Origin: https://foo.bar.org如果服务器允许,那么服务器就会响应这个预检请求。并且其响应首部
Access-Control-Allow-Methods会将DELETE包含在其中:HTTP/1.1 200 OK Content-Length: 0 Connection: keep-alive Access-Control-Allow-Origin: https://foo.bar.org Access-Control-Allow-Methods: POST, GET, OPTIONS, DELETE Access-Control-Max-Age: 86400