NGINX 的核心架構採用模組化設計,允許開發者根據需求選擇和組態不同的模組。這使得 NGINX 非常靈活,可以適應各種不同的應用場景。文章首先介紹了 NGINX 模組的分類別,包括預設啟用、編譯時啟用以及第三方模組。接著,重點探討了 Rewrite 模組的功能,說明如何利用正規表示式進行 URL 重寫,以及如何藉此提升網站的 SEO 和使用者經驗。更進一步地,文章詳細解釋了正規表示式的基本語法,包含各種元字元、數量詞以及捕捉群組的用法,並輔以實際案例說明如何在 NGINX 組態中有效運用這些技巧。最後,文章還區分了 NGINX 處理外部請求和內部請求的差異,並提供相關指令和組態範例,讓讀者更全面地理解 NGINX 的運作方式。

模組組態探索:NGINX的核心功能

NGINX的真正強大之處在於其模組系統。整個應用程式都是建立在模組化架構上,每個模組都可以在編譯時啟用或停用。有些模組提供簡單的功能,例如 autoindex 模組,它可以生成目錄中的檔案列表。而有些模組則會完全改變你對網頁伺服器的認知,例如 Rewrite 模組。除了現有的 NGINX 模組外,開發者還可以根據需要建立自己的模組。

在本章末尾,你可以找到第三方模組系統的快速概述。請注意,第三方模組由社群維護,並不保證這些模組會與你的 NGINX 版本相容。

本章涵蓋以下主題:

  • Rewrite 模組:不僅僅是重寫 URI
  • 預設 NGINX 版本中啟用的其他模組
  • 必須在編譯時啟用的可選模組
  • 第三方模組的簡要說明

深入探索 Rewrite 模組

Rewrite 模組為 NGINX 帶來了遠超過簡單指令集的功能。它定義了一個全新的請求處理層級,這一部分將在接下來的內容中詳細說明。

首先,這個模組(如名稱所暗示)用於進行 URL 重寫。這個機制允許你去除包含多個引數的醜陋 URL,例如 http://example.com/article.php?id=1234&comment=32。這些 URL 對一般訪客來說特別不具資訊量且無意義。

相反地,連結到你網站的 URL 將包含有用的資訊,指示即將存取的頁面性質。例如,URL http://website.com/article-1234-32-US-economy-strengthens.html 不僅對訪客更有趣,對搜尋引擎也更友好。URL 重寫是搜尋引擎最佳化(SEO)的關鍵元素。

這個機制的原理非常簡單:它是在接收到客戶請求後、提供檔案前重寫請求 URI。重寫後,URI 會與位置區塊進行比對,以找到應用於請求的組態。這項技術將在後續部分中詳細說明。

正規表示式回顧

首先,這個模組需要一定程度上的正規表示式(regex 或 regexp)理解。因為 URL 重寫是透過 rewrite 指令完成的,該指令接受一個模式後跟隨替換 URI。

這是一個廣泛的話題;有整本文專門解釋其奧妙。然而,我們即將檢視的簡化方法應該足夠讓你充分利用這個機制。

正規表示式的目的

我們首先要回答的問題是:正規表示式的目的是什麼?簡單來說,其主要目的是驗證一個字串是否比對給定模式。該模式使用特定語言來定義極其複雜且精確的規則:

字串模式是否比對說明
hello^hello$字串從 h 開始(^h),接著是 e, l, l ,然後以 o 結束(o$)。
hell^hello$字串從 h 開始(^h),接著是 e, l, l ,但不以 o 結束。
Hello^hello$未知若執行比對的是區分大小寫引擎,則字串不比對該模式

表格4.1:包含說明的一些模式

當使用更複雜的模式時,這一概念變得更加有趣。例如:驗證電子郵件地址: ^[A-Z0-9._%+-]+@[A-Z0-9.-]+.[A-Z]{2,4}$。程式化驗證一個合法電子郵件地址可能需要大量程式碼,而所有工作都可以透過單一正規表示式進行。

PCRE 語法

NGINX 使用的是 Perl Compatible Regular Expressions (PCRE) 函式庫語法(如果記得第2章),這對於自行構建 NGINX 是必需的一項前提條件,除非你停用使用它們的模組。它是最常見的一種正規表示式形式,幾乎所有你學到的是都適用於其他語言變體。

在最簡單形式下,一個模式由一個字元構成——例如 x。我們可以將字串與該模式進行比對。“example” 比對 x 模式嗎?是的,“example” 包含字元 “x”。它還可以是多個特定字元;[a-z] 模式比對 a 和 z 之間任意一個字元, 或甚至是字母和數字的混合: [a-z0-9]。因此, “hell[a-z0-9]” 模式驗證以下字串: “hello” 和 “hell4”,但不包括 “hell” 或 “hell!"。

你可能已經注意到我們使用了 [ 和 ] 段落符號,它們被稱為元字元, 對於讓語法更具指導性起著重要作用。總共有11種元字元,每個都扮演著不同角色。 若要建立實際包含其中之一元字元,必須逃避該段落 (\反斜槓):

元字元說明
^開始
此字元後面必須是開頭:
• 範例段落: ^h
• 比對範例: hello, h, hh (任何以 h 開始)
• 不比對範例: character, ssh
$結果
此字元前面必須位於結尾:
• 範例段落: e$
• 比對範例: sample, e, file (任何以 e結尾)
• 不比對範例: extra, shell
. (點)任意
比對任何字元:
• 範例段落: hell.
• 比對範例: hello, hellx, hell5 和 hell!
• 不比對範例: hell 和 helo

自行建立最適合需求之自定義 Rewrite 條件

玄貓認為解析清楚 Rewrite 的內容後就可以輕鬆地使用其指令進行適當調整。 Rewrite 條件可以根據 URL、HTTP Header、變數等多種條件進行判斷。 以下是幾個常見條件及其應用情境:

# 根據 URL 的條件
rewrite ^/old-path/(.*) /new-path/$1 break;
# 根據 HTTP Header 的條件
if ($http_user_agent ~* MSIE) {
    rewrite ^(.*)$ /ie/$1 break;
}
# 根據變數值判斷
set $my_var "value";
if ($my_var = "value") {
    rewrite ^(.*)$ /custom/$1 break;
}

內容解密:

上述程式碼展示瞭如何根據不同條件進行重寫操作。

  1. 第一段程式碼中,NGINX 檢查請求 URL 是否以 /old-path/ 開始。 如果比對成功則會將 /old-path/ 則替換為 /new-path/
  2. 第二段程式碼中檢查 HTTP Header 中 User-Agent 是否包含 MSIE。 如果比對成功則將所有請求轉向 /ie/ 下。
  3. 第三段程式碼中會先設定變數 $my_var 的值為 value。 然後再檢查 $my_var 是否等於 value。 如果條件成立則轉向 /custom/ 下。

玄貓認為只要稍微瞭解一下 Rewrite 指令和常見條件, 就能根據實際需求構建出最適合自己的 Rewrite 組態。 以上示範了幾種常見情境及其應對策略, 希望能夠幫助大家更好地掌握 Rewrite 的使用技巧, 進而提升網站管理和最佳化能力。

Mermaid

  graph TD;
    A[客戶端請求] --> B{URL 比對};
    B -- 比對成功 --> C[URI 轉向];
    B -- 比對失敗 --> D[直接處理];
    C --> E[位置區塊];
    D --> E;

內容解密:

此圖示展示了 NGINX 在處理客戶端請求時如何透過 URI 轉向來決定應用哪些位置區塊。當客戶端發出請求時(A),NGINX 首先檢查 URL 是否與重寫規則比對(B)。如果比對成功(C),URI 會被轉向到新位置;如果未比對(D),則直接處理原始請求並應用相應位置區塊(E)。

NGINX 的 Rewrite 模組提供了靈活且強大的功能來處理和轉發 HTTP 請求。透過理解和掌握這些功能,我們可以實作更高效和可靠的網站伺服器管理和最佳化。玄貓希望透過深入瞭解和實踐 NGINX 的 Rewrite 模組功能來提升網站效能和使用者經驗。

NGINX 正規表示式與重寫模組深度探索

NGINX 是一個強大的網頁伺服器,其功能強大且靈活,特別是在處理 URL 重寫和正規表示式時。本文將探討 NGINX 中的正規表示式及其在重寫模組中的應用,並提供實際案例和詳細解說。

正規表示式元字元

正規表示式是一種強大的工具,能夠用來比對和操作文字。以下是一些常見的元字元及其在 NGINX 中的應用:

  • [ ]:字元集

    • 說明:比對指定集合中的任何字元。
    • 語法:[a-z] 表示比對任何小寫字母,[abcd] 表示比對 abcd[a-z0-9] 表示比對任何小寫字母或數字。
    • 範例模式:hell[a-y123-]
    • 比對字串:hellohell1hell2hell3hell-
    • 不比對字串:hellzhell4heloohe-llo
  • [^ ]:否定字元集

    • 說明:比對不在指定集合中的任何字元。
    • 語法:[^a-np-z0-9]
    • 比對字串:hellohell!
    • 不比對字串:hellahell5
  • |:替代

    • 說明:比對 | 前後的任一模式。
    • 語法:hello|welcome
    • 比對字串:hellowelcomehelloesawelcome
    • 不比對字串:helloelloeslo, ellow, owelcom.
  • ( ):分組

    • 說明:將多個模式分組,通常用於替代或捕捉。
    • 語法:^(hello|hi) there$
    • 比對字串:'hello there''hi there'
    • 不比對字串:'hey there''ahoy there'
  • \:轉義

    • 說明:用於轉義特殊字元,使其成為普通字元。
    • 語法:'Hello\\'
    • 比對字串:'Hello.' 不比對字串: ‘Hello’, ‘Hello!how are you?’

數量詞

數量詞允許您擴充套件接受的實體數量。以下是一些常見的數量詞及其應用:

  • *:0 次或多次

    • 說明: 前面的實體可以出現0次或多次
    模式: he*llo
    比對: hllo, hello, heeeello
    不比對: hallo, ello
    
  • +:1 次或多次

    模式: he+llo
    比對: hello, heeeello
    不比對: hllo, helo
    
  • ?****:0 次或1次

    模式: he?llo
    比對: hello, hllo
    不比對: heello, heeeello
    
  • {x}:x 次

    模式: he{3}llo
    比對: heeello, oh heeello there!
    不比對: hello, heello, heeeello
    
  • {x,}:至少 x 次

    模式: he{3,}llo
    比對: heeello, heeeeeeello
    不比對: hllo, hello, hello
    
  • {x,y}:x到y次**

    模式: he{2,4}llo
    比對: heello, heeello, heeeello.
    不比對: hello, heeeeello.
    

由於 NGINX 組態檔案語法中的大括號會與正規表示式中的大括號衝突,因此需要將包含大括號的模式放在引號中:

rewrite hel{2,}o /hello.php; # 無效的寫法

rewrite "hel{2,}o" /hello.php; # 有效的寫法

rewrite 'hel{2,}o' /hello.php; # 有效的寫法

捕捉群組

捕捉群組是正規表示式的一個強大功能,允許您捕捉子表示式並將其儲存在變數中。這些變數可以在後續指令中使用。

例如:

模式: ^(hello|hi) (sir|mister)$

比對字串: 'hello sir'

捕捉結果:
$1 = hello,
$2 = sir.
模式 : ^(.*)$
比對字串:'nginx rocks'
捕捉結果:
$1=nginx rocks.

捕捉命名

NGINX 支援使用命名捕捉來提高可讀性。例如:

模式 : ^/(?<folder>[^/]+)/(?<file>.*)$

url : '/admin/doc'

捕捉結果:
$folder = admin,
$file = doc.

在 NGINX 中應用正規表示式

在 NGINX 中,您可以在 location 塊中使用正規表示式來比對請求 URI。例如:

server {
server_name website.com;
location ~* ^/(downloads|files)/(.*)$ {
add_header Capture1 $1;
add_header Capture2 $2;
}
}

在這個例子中,當請求 URI 與正規表示式 /downloads/file.txt, /files/archive.zip, 或 /files/docs/report.doc.時會被捕捉到:

$1 = downloads or files,
$2 = file.txt or archive.zip or report.doc.

外部與內部請求

NGINX 做出了外部請求與內部請求之間的區別。外部請求直接來自客戶端並被比對可能的 location 塊。

server {
server_name website.com;
location = /document.html {
deny all; # 測試指令.
}
}

#這樣一來當客戶端請求 http://website.com/document.html.時就會被拒絕連線.

內部請求由 NGINX 本身觸發,並且需要具備特定的指令才能產生。例如:

error_page, index, rewrite, try_files,
add_before_body and add_after_body (from the addition module)
Server-Side Includes (SSI) command.