Nginx的跨源/跨域配置宏cors_params

背景

网上搜到的很多Nginx CORS配置虽然也起作用,但是可能因未参考规范而缺少基本的逻辑判断,不能表达CORS的工作原理。

Tomcat中有参考自CORS specification的CORS实现CorsFilter,用起来非常方便,故我想把Tomcat CorsFilter的逻辑照搬到Nginx中。

然而不巧的是,Nginx的if指令不支持逻辑与而导致多条件判断非常吃力,加之If is Evil… when used in location context,还有add_header指令不继承上层add_header也让人头疼。最终选用headers-more模块more_set_headers来设置响应头,虽然不支持追加响应头,但因只需追加Vary响应头,故最中通过加一个map指令块解决。

以Debian/Ubuntu系统为例,使用步骤如下:

前提准备

安装Nginx,并安装Nginx模块headers-more

apt-get install nginx-full
apt-get install libnginx-mod-http-headers-more-filter

或自行编译的Nginx,configure时添加模块headers-more

配置

/etc/nginx/conf.d/cors.conf

map $http_origin $allow_origin {
  # 允许私有网段IP
  ~^http://(192\.168|172\.(1[6-9]|2[0-9]|3[0-1])|10\.\d+)\.\d+\.\d+(:\d+)?$ $http_origin;
  # 允许本机
  ~^http://(127\.0\.0\.1|localhost)(:\d+)?$ $http_origin;
  # 允许*.example.com
  ~^https?://[a-z0-9-]+\.example\.com$ $http_origin;
  default '';
}
map $sent_http_vary $comma_vary {
  default "";
  ~.+ ",$sent_http_vary";
}

/etc/nginx/cors_params

# 需要在nginx.conf中  `include conf.d/*.conf` 或 `include conf.d/cors.conf`;

# preflight request
if ($http_access_control_request_method != "") {
  more_set_headers "access-control-allow-origin: $allow_origin";
  more_set_headers "access-control-allow-methods: $http_access_control_request_method";
  # necessary only if 'http-access-control-request-headers' present
  more_set_headers "access-control-allow-headers: $http_access_control_request_headers";
  # necessary only if 'access-control-request-credentials' present
  # more_set_headers "access-control-allow-credentials: true";
  # necessary only if 'access-control-request-private-network' present
  # more_set_headers "access-control-allow-private-network: true";
  # can be up to 5 if 'access-control-request-private-network', up to 600 otherwise
  more_set_headers "access-control-max-age: 600";
  more_set_headers "vary: origin$comma_vary";
  return 204;
}

# actual request
if ($http_origin != "") {
  more_set_headers "access-control-allow-origin: $allow_origin";
  more_set_headers "access-control-expose-headers: accept-ranges,content-range,last-modified,etag";
  # to support Resource Timing API
  # more_set_headers "timing-allow-origin: $allow_origin";
  more_set_headers "vary: origin$comma_vary";
}

需要注意的是:不久的将来各浏览器将默认启用PNA preflight策略,到时对于私有网络(例如192.168.*.*, 172.16~31.*.*, 10.*.*.*)以及本机127.*.*.*的源,浏览器在发送的preflight请求时会携带请求头access-control-request-private-network: true,而服务端需要添加响应头access-control-allow-private-network: true以改进支持。

调用

/etc/nginx/sites-enabled/example.com.conf

server {
  # ...
  location / {
    root /var/www/example.com;
    include cors_params; # 放在location块尾端
  }
  location /api/ {
    proxy_pass http://localhost:8080/api/;
    include proxy_params;
    include cors_params; # 放在location块尾端
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值