nginx: Core Concept

 15th February 2022 at 6:46pm

先看 Nginx Tutorial #1 Basic Concepts(链接存档)讲得清晰明了。

不在任何 context 下的 directive 被称为 global configuration directive。这些 directive 也可以通过 nginx 命令行来配置。

如何判断一个请求被哪个 server 及 location 处理?官方文档 有描述具体的逻辑。Digital Ocean 也有一篇非常详细的 讲解文章。这是 nginx 中比较复杂的一环。

location 匹配

location context 一般的样式是:

location <optional_modifier> <location_match> {
    # ...
}

比如:

location ~ \.(jpe?g|png|gif|ico)$ {
    # ...
}

modifier 是针对 location 而言的(不对其他 directive 通用),有 4 种,官方文档 有描述,Digital Ocean 的 文档 也有非常好的描述。总结如下:

不指定普通字符串,前缀匹配
=普通字符串,精确匹配,优先级最高
~正则表达式,区分大小写匹配
~*正则表达式,不区分大小写匹配
^~普通字符串,前缀匹配;一旦匹配成功,不再走正则表达式匹配

location 匹配逻辑如下:

  1. 如果有普通字符串精确匹配(=),使用这个 location
  2. 找到最长的普通字符串前缀匹配,记录下来
  3. 如果这个最长匹配是 ^~,使用这个 location;否则依次执行正则匹配,使用第一个匹配成功的 location
  4. 找不到任何匹配的 location 时,返回 404

正则表达式

nginx 使用了 PCRE 库来处理 regexp。配置中对 regexp 的使用不够有一致性,比如:

# location 使用了一个单独的 modifier 来表示是否为一个 regexp:
location ~* \.(gif|jpg|jpeg)$ {
    # ...
}

# server_name 及 map 则使用了 ~ 或者 ~* 来表示一个 regexp:
server {
    listen       80;
    server_name  ~^(?<user>.+)\.example\.net$;
    ...
}
map $uri $isphp {
    ~\.php$ 1;
    default 0;
}

这点是反直觉的。nginx 的正则能力并不是通用的(universal),而是跟具体的 directive 是否支持、如何支持有关。