在 nginx 中,如果存在多个监听同一个端口的 server 块的话,nginx 就会通过 server_name 去匹配 request 中的 Host header 的值来确定到底要交给哪一个 server 块进行处理。
server {
listen 80 default_server;
server_name _;
...
}
server {
listen 80;
server_name xxx.com www.xxx.com;
...
}
在上面的配置文件中,如果 request 的 Host header 的值为 xxx.com 或者为 www.xxx.com 的话,就会把这个请求交给第二个 server 块处理,否则就会都交给第一个 server 块处理。
但是在很多的配置文件中,会经常看到 server_name "" 与 server_name _ 这样的指令。
之所以我会对 server_name "" 与 server_name _ 感到困惑,是因为一开始在我的潜意识里不管是 server_name "" 还是 server_name _ 都是可以用来匹配所有的 Host header 值的,但是我又找不到资料来作证我的想法。但是后来我发现其实我一开始对 server_name "" 与 server_name _ 的理解是不正确的。
server_name ""
nginx 的官方文档是这么描述 server_name "" 的:
If it is required to process requests without the “Host” header field in a server block which is not the default, an empty name should be specified.
也就是说,如果想让一个没有被标注为 default_server 的 server 块来处理一个没有带有 Host header 的请求的话,就需要使用 server_name "" 指令。但是问题是,HTTP/1.1 (也就是当前主流的 HTTP version)中规定,如果一个请求没有带有 Host header 的话,服务器必须得返回 400(Bad Request):
所以说,使用了 server_name "" 的非 default server 块压根就没有机会去处理一个没有带有 Host header 的请求,因为在把这个请求交给 server 块之前就已经先被 nginx 处理然后返回 400 状态码了。
所以我现在认为 server_name "" 本身是没有意义的,因为它根本就匹配不了任何 Host header 的值。
所以说单独使用一个 server_name "" 的 server 块是处理不了任何请求的,它通常要跟 listen default_server 配合使用,表示这个 server 块可以集中处理那些无法被其他 server 块处理的请求。
server_name _
server_name _ 是可以匹配到 Host header 的值的,因为它可以匹配到 Host header 值为 _ 的请求。但是这种匹配其实也是没有意义的,因为对于浏览器而言,请求中的 Host header 的值就是你所输入的网站地址(可以是 IP 地址也可以是域名),但是 "_" 根本就不是一个域名,它根本就无法被解析成 ip 地址,无法被解析成 ip 地址就意味着这个请求根本就没办法发送到对应的服务器上,所以 server_name _ 跟 server_name "" 一样根本就没有用武之地。
所以我认为 server_name _ 跟 server_name "" 一样本身是没有任何意义的,其实除了 server_name _ 之外,也可以是 server_name $ 、 server_name @ 等等。
所以跟 server_name "" 一样,单独使用 server_name _ 的 server 块是处理不了任何请求的,一般也是要跟 listen default_server 一起配合使用,表示这个 server 块可以集中处理那些无法被其他 server 块处理的请求。