How nginx processes a request

【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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章