How nginx processes a request
  wROjKzsxjeRY 2023年11月02日 46 0

【1】基于名字的虚拟server

首先看下面三个简单配置(这三个虚拟server配置均是监听80端口,server_name不同):

server {
listen 80;
server_name example.org www.example.org;
...
}

server {
listen 80;
server_name example.net www.example.net;
...
}

server {
listen 80;
server_name example.com www.example.com;
...
}

当nginx接收到一个请求,会首先拿到请求头的Host字段值来判断请求路由到哪个server上面。如果没有server_name匹配Host值或者说请求头根本没有Host字段,nginx将会路由该请求到80端口的默认server上面。在上面配置中,默认server-default server 是第一个–这是nginx的默认行为。当然,你可以直接在listen 指令中使用default_server 参数指定该server为default server,如下所示:

server {
listen 80 default_server;
server_name example.net www.example.net;
...
}

自从0.8.21版本后使用default_server,以前版本使用default 参数。

通常情况下,请求头中无Host字段是不被允许的,应该直接丢弃。这时就可以配置一个空server_name来处理这种情况,如下所示:

server {
listen 80;
server_name "";
return 444;
}

在0.8.48版本后,server_name默认值就是​​""​​,所以不设置也可以。在该版本前,默认值为机器的hostname。


【2】基于名字和IP地址的虚拟server

如下所示,有三个相对复杂的server配置:

server {
listen 192.168.1.1:80;
server_name example.org www.example.org;
...
}

server {
listen 192.168.1.1:80;
server_name example.net www.example.net;
...
}

server {
listen 192.168.1.2:80;
server_name example.com www.example.com;
...
}

当nginx接收到一个请求后,首先会拿着请求的IP地址与端口和server的listen指定配置进行比较。如果​​IP:PORT​​​匹配成功,然后会把请求头的Host字段值与server块的server_name进行匹配。如果server_name没有匹配成功,那么请求将会被默认server处理。比如192.168.1.1:80接收到了一个请求www.example.com,因为该​​IP:PORT​​上面没有匹配的server_name,那么第一个server将会作为default server 处理这个请求。

如前所述,默认服务器是侦听端口的属性,可以为不同端口定义不同的默认服务器:

server {
listen 192.168.1.1:80;
server_name example.org www.example.org;
...
}

server {
listen 192.168.1.1:80 default_server;
server_name example.net www.example.net;
...
}

server {
listen 192.168.1.2:80 default_server;
server_name example.com www.example.com;
...
}

以上内容参考:​​How nginx processes a request​


【3】Server Name如何匹配?

在server块中用server_name指令定义server name,nginx使用server name决定当前接收到的请求使用哪个server 块来处理。server name有三种定义方式:精确值、通配符以及正则表达式。

实例如下:

server {
listen 80;
server_name example.org www.example.org;
...
}

server {
listen 80;
server_name *.example.org;
...
}

server {
listen 80;
server_name mail.*;
...
}

server {
listen 80;
server_name ~^(?<user>.+)\.example\.net$;
...
}

server name匹配规则为(优先级从上到下):

  • 精确值
  • ​*​​​开头的、最长的通配符名称,如​​*.example.org​
  • ​*​​​结尾的、最长的通配符名称,如​​mail.*​
  • 配置文件从上到下顺序第一个匹配的正则表达式

当server_name是一个正则表达式时,必须以​​~​​​作为首字母。如果包含​​*​​​就会作为通配符格式名字,否则就被作为精确名字进行对待。使用正则表达式时别忘了​​^ $​​符号。


复杂的server name

有一些server name需要特殊对待。

如果当前server(非 default server)需要处理请求(没有Host请求头),那么可以指定一个空的server_name:

server {
listen 80;
server_name example.org www.example.org "";
...
}

如果server块中没有定义server_name,那么默认使用空​​""​​作为server name。在本例中,0.8.48之前的nginx版本使用机器的主机名作为服务器名。

如果server name值为 ​​“$hostname”​​ (0.9.4), 那么机器的hostname作为server name。

如果请求是使用IP地址而不是域名,那么请求头的Host字段将会包括IP地址。请求就会被使用ip地址作为server_name的server块处理,如下所示:

server {
listen 80;
server_name example.org
www.example.org
""
192.168.1.1
;
...
}

在其他一些实例中可能看到奇怪的server name ​​_​​,如下所示:

server {
listen 80 default_server;
server_name _;
return 444;
}

这个server name没有什么特别的,它只是无数无效域名中的一个,永远不会与任何真实的名字相交。其他无效域名像​​“--” and “!@#”​​也是一样道理。

nginx0.6.25 版本以前支持使用特殊的名字​​*​​​,改名称被错误的作为server_name来匹配所有的server name。现在已经过期了,server_name不再支持​​*​​​作为server name。但是可以在listen属性中使用,如​​*:80 and *:8080​​。


优化特性

精确名称、以星号开头的通配符名称和以星号结尾的通配符名称存储在绑定到侦听端口的三个哈希表中。哈希表的大小在配置阶段进行了优化,以便在CPU缓存未命中最少的情况下找到名称。设置hash表的详细信息在一个单独的文档中描述,​​Setting up hashes​​。

首先从精确名称对应的hash表里面查找,如果找不到server name将会从​​*​​​开头通配符名称对应的hash表开始查找。如果仍然没有找到server name,则将会从以星号结尾的通配符名称对应的hash表搜索。搜索通配符名称哈希表比搜索精确名称哈希表慢,因为名称由域部分搜索。需要注意的是,特殊的通配符格式​​“.example.org”​​存储在通配符名称hash表中而不是精确名称hash表中。

因为正则表达式是按序从上到下匹配,所以这种方式是最慢且不可扩展的。

故而,请尽可能使用精确名称定义server name。例如,如果经常请求服务名称为​​example.org and www.example.org​​,如下两种方式效率截然不同(前者远优异于后者):

server {
listen 80;
server_name example.org www.example.org *.example.org;
...
}

server {
listen 80;
server_name .example.org;
...
}

如果定义了大量服务器名称,或者定义了异常长的服务器名称,则可能需要在http级别调整server_names_hash_max_size和server_names_hash_bucket_size指令。server-names-hash-bucket-size指令的默认值可以等于32、64或其他值,具体取决于CPU缓存线大小。如果默认值为32,服务器名定义为“too.long.server.name.example.org“然后nginx将无法启动并显示错误消息:

could not build the server_names_hash,
you should increase server_names_hash_bucket_size: 32

在这种情况下,指令值应该设置为当前的2倍:

http {
server_names_hash_bucket_size 64;
...

如果大量server name被定义,nginx可能显示如下错误信息:

could not build the server_names_hash,
you should increase either server_names_hash_max_size: 512
or server_names_hash_bucket_size: 32

在这种情况下,首先尝试将server_names_hash_max_size大小设置为接近server name数量的数字。只有当这不起作用,或者nginx的启动时间过长时,才尝试增加server_names_hash_bucket_size的大小。

**如果这个server是唯一一个监听对应​​IP:PORT​​的server,那么将不会再匹配server name!同样也不会为监听的端口创建hash表。**然而,有一个例外。如果服务器名是带有捕获的正则表达式,那么nginx必须执行该表达式才能获取捕获。


一些兼容性配置

  • The special server name​​“$hostname”​​ has been supported since 0.9.4.
  • A default server name value is an empty name​​""​​ since 0.8.48.
  • Named regular expression server name captures have been supported since 0.8.25.
  • Regular expression server name captures have been supported since 0.7.40.
  • An empty server name​​""​​ has been supported since 0.7.12.
  • A wildcard server name or regular expression has been supported for use as the first server name since 0.6.25.
  • Regular expression server names have been supported since 0.6.7.
  • Wildcard form example.​​*​​ has been supported since 0.6.0.
  • The special form​​.example.org​​ has been supported since 0.3.18.
  • Wildcard form​​*.example.org​​ has been supported since 0.1.13.

参考官网:​​Server names​


【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

推荐阅读
  bifOjSxj34Bv   2023年12月07日   36   0   0 nginxDockerdockernginx
wROjKzsxjeRY