一、起因查找

今天发现有个前后端分离站点通过nginx转发原以为是普通的跨域问题,就简单的在配置里加上了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
   location /API {
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Headers 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,_tag_,';
add_header Access-Control-Allow-Methods GET,POST,OPTIONS,HEAD,PUT;
add_header Access-Control-Allow-Credentials true;

proxy_set_header x-real-ip $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

if ( $request_method = 'OPTIONS' ) {
return 200;
}
proxy_pass http://66.66.66.66:8888/API;


}

修改完发现无效果,遂去检查一下后端的跨域配置,也无果

二、原因分析

查了一下发现是nginx在代理转发默认会把header头中的参数带有下划线:_ 的自定义字段省略掉,所以后端就获取不到带下划线:_ 的自定义参数名,我这里传的参数这好歹下划线

看一下ng的官网对于客户端请求标头字段中启用或禁用下划线的说明 http://nginx.org/en/docs/http/ngx_http_core_module.html#underscores_in_headers

机翻一下

大体意思是默认的情况下会忽略掉带下划线的变量。要解决这个需要配置 underscores_in_headers off 改为 on

我们在继续查看一下ng的源码,https://trac.nginx.org/nginx/browser/nginx/src/http/ngx_http_parse.c

在ngx_http_parse_header_line() 的函数下面是这样的

1
2
3
4
5
6
7
8
9
10
11
12
13
ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b,ngx_uint_t allow_underscores)

if (ch == '_') {
if (allow_underscores) {
hash = ngx_hash(0, ch);
r->lowcase_header[0] = ch;
i = 1;
} else {
r->invalid_header = 1;
}
break;
}

也可以发现其中allow_underscores 是否允许下划线这个选项

so

三、解决方案

在前后端nginx配置中添加

1
underscores_in_headers on;

nginx配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
server
{
listen 80;
server_name api.2021.com;

underscores_in_headers on; #这里添加

#REWRITE-END
location / {

proxy_pass http://66.66.66.66:8888;

}

#禁止访问的文件或目录
location ~ ^/(.user.ini|.htaccess|.git|.svn|.project|LICENSE|README.md)
{
return 404;
}


access_log /usr/local/nginx/logs/api.2021.com.log;
error_log /usr/local/nginx/logs/api.2021.com.error.log;
}

就OK了