下划线不是一个合法的hostname字符
根据 RFC952 的标准:
A “name” (Net, Host, Gateway, or Domain name) is a text string up to 24 characters drawn from the alphabet (A-Z), digits (0-9), minus sign (-), and period (.). Note that periods are only allowed when they serve to delimit components of “domain style names”.
下划线并不在合法字符之列,但是现实中很多系统是可以支持带有下划线的hostname的,这反而容易引起误解。
在项目中发现,当 nginx 设置了 upstream 进行负载均衡的反向代理时,upstream 的名称会被当作 hostname 发送到后端,例如:
upstream app_servers {
server 10.33.70.214:443;
server 10.100.12.10:443;
}
...
location /abc {
proxy_pass https://app_servers;
}
这时 nginx 会将 app_servers 作为 hostname 发送到后端,我们的后端使用的是 uwsgi ,这个软件就不支持域名中带有下划线。结果是转发后直接报错 400 ,实测结果如下:
curl -k -H 'Host: app_servers' https://localhost:19000/
<!doctype html>
<html lang="en">
<head>
<title>Bad Request (400)</title>
</head>
<body>
<h1>Bad Request (400)</h1><p></p>
</body>
</html>
值得一提的是当向AI咨询 nginx load balance 时,AI给出的例子中,upstream 的名称就是带有下划线的,而nginx的官网中的例子都是没有下划线的。这也是AI对错误知识的一个传播。
在查询相关信息时,还发现了另外一个信息,nginx 默认会丢弃名称中带有下划线的 http header。
所以在设置自定义的 http header 时,尽量不要使用下划线。
虽然根据规范,http header 的名称中下划线是合法的,但为了兼容 CGI 程序,nginx默认会丢弃这种header。
可以通过设置 underscores_in_headers on; 来让 nginx 接受这种 header,但在复杂的系统环境中,最好还是避免对nginx的这种要求。