Access-Control-Allow-Headers
当浏览器发送接口请求出现跨域问题时,目前的做法通常会在接口服务器增加如下配置。
Access-Control-Allow-Origin: *
但是有时也会出现 Access-Control-Allow-Headers
的错误问题。
Access to XMLHttpRequest at'http://www.xxx.com/api' from origin 'http://localhost:8080' has been blocked by CORS policy: Request header field content-type is not allowed by Access-Control-Allow-Headers in preflight response.
下面我们就来分析一下原因和解决办法。
原因
浏览器在发送跨域请求并且包含自定义 header 字段时,浏览器会先向服务器发送 OPTIONS 预检请求(preflight request),探测该请求服务是否允许自定义跨域字段。
如果允许,则继续执行 POST、GET请求,否则返回提示错误。
OPTIONS 请求:
Request URL:http://xxx.com/api
Request Method:OPTIONS
Status Code:200 OK
Remote Address:00.00.00.00:80
Referrer Policy:no-referrer-when-downgrade
Request Header:
Accept:*/*
Accept-Encoding:gzip, deflate
Accept-Language:zh-CN,zh;q=0.9,en;q=0.8
Access-Control-Request-Headers:content-type,xfilecategory,xfilename,xfilesize
Access-Control-Request-Method:GET
Connection:keep-alive
Host:http://localhost:8080/
Origin:http://localhost:8080/
User-Agent:Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1
注意⚠️
此时浏览器会向服务器发送预检请求,询问是否支持跨域的自定义 header 字段。设置的 Access-Control-Request-Headers
服务器需要适当的作出应答。
服务器应答方式
服务器需要对 OPTIONS 请求作出应答,通过设置 header 包含 Access-Control-Request-Headers
,并且包含 OPTIONS 请求中的 Access-Control-Request-Headers
对值。
例如:
response.setHeader("Access-Control-Allow-Headers", "Content-Type,Access-Token");
另外(其实很重要)
如果你对请求是 simple headers 方式则不会发送预检请求。
- Accept
- Accept-Language
- Content-Language
- Content-Type
当仅包含以上这些请求头(以及满足下面列出的附加要求的值)时,请求不需要在 CORS 的上下文中发送预检请求。
附加要求
CORS 安全标头还必须满足以下要求才能成为 CORS 安全的请求标头:
- 对于
Accept-Language
和Content-Language
:只能存在值0-9
,A-Z
,a-z
,空间或*,=.;=
。 - 关于
Accept
和Content-Type
:不能包含 CORS 不安全的请求头字节:"():<>?@[\]{}
,Delete
,Tab
和控制字符:0x00
到0x19
。 Content-Type
:需要有一个 MIME 类型的值(忽略参数)。可以是application/x-www-form-urlencoded
、multipart/form-data
或text/plain
的任意一个。- 对于任何
header
:值的长度不能大于 128。
通常影响程序发送预检请求的总是 Content-Type
的设置。如果我们在跨域请求时不需要发送预检请求,那么可以通过设置浏览器请求 Content-Type
为 application/x-www-form-urlencoded
、multipart/form-data
或 text/plain
的任意一个来避免。
例如:
headers.set('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
参考
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Access-Control-Allow-Headers https://developer.mozilla.org/en-US/docs/Glossary/CORS-safelisted_request_header https://stackoverflow.com/questions/25727306/request-header-field-access-control-allow-headers-is-not-allowed-by-access-contr
