环境
Nginx v1.27.1
安装了 Lua 模块,因为 Access-Control-Expose-Headers
原生 nginx 没有提供内置变量来动态获取设置其值
发现以前处理的还是太粗糙了,直接写死固定值,或者通配符值 *
,但是 *
限制很多,仅在满足特定请求方法、指定要求下才会生效
典型场景,当
Access-Control-Allow-Credentials
的值为true
Access-Control-Allow-Origin
Access-Control-Allow-Headers
Access-Control-Expose-Headers
Access-Control-Allow-Methods
上述 4 个字段,值设置为 *
,仅在无凭据的请求(即不包含 HTTP cookie 或 HTTP 认证信息的请求)中视为特殊的通配符值。在带有凭据的请求中,它被当作字面意义的标头名称“*”处理,不具有特殊语义,会报错为Credential is not supported if the CORS header 'Access-Control-Allow-Origin' is '*'
expected 'true' in CORS header 'Access-Control-Allow-Credentials'
Did not find method in CORS header 'Access-Control-Allow-Methods'
而且对于 Access-Control-Expose-Headers
,即使不带 Access-Control-Allow-Credentials
, Authorization
字段仍然需要显示指定
所以可以使用 nginx 内置变量动态获取设置这些字段的值,以便实现最大兼容
最终配置,我们可以把它写入一个文件 cors.conf
,然后使用 include
在 location
中多次引用
#Allow all requset/method/header/custom credentials
add_header 'Access-Control-Allow-Origin' $http_origin always;
add_header 'Access-Control-Allow-Headers' $http_access_control_request_headers always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
add_header 'Access-Control-Allow-Methods' $http_access_control_request_method always;
add_header 'Access-Control-Max-Age' 86400 always;
if ($request_method = 'OPTIONS') {
return 204 always;
}
对于 Access-Control-Expose-Headers
,使用 Lua 来处理,自动暴露所有返回的响应头
location /api/ {
header_filter_by_lua_block {
local expose_headers = {}
-- 使用 ngx.resp.get_headers() 获取所有响应头
for header, _ in pairs(ngx.resp.get_headers()) do
table.insert(expose_headers, header)
end
ngx.header["Access-Control-Expose-Headers"] = table.concat(expose_headers, ", ")
}
}
创建一个空表 expose_headers 来存储头部信息
遍历当前响应中的所有 HTTP 头部(ngx.resp.get_headers)
将每个头部名称添加到 expose_headers 表中
最后将所有头部名称用逗号连接起来,设置为 Access-Control-Expose-Headers 响应头的值
最后实现了自动把所有响应头都暴露给前端访问