飘在云端

东西南北,海角天涯

· 前端 · · 27次浏览

nginx 使用内置变量动态获取设置 CORS 跨域的值

环境
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-CredentialsAuthorization 字段仍然需要显示指定

所以可以使用 nginx 内置变量动态获取设置这些字段的值,以便实现最大兼容
最终配置,我们可以把它写入一个文件 cors.conf,然后使用 includelocation 中多次引用

#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 响应头的值
最后实现了自动把所有响应头都暴露给前端访问

评论 (0条)