社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  NGINX

理解Nginx中Server和Location的匹配逻辑

小米运维 • 5 年前 • 333 次点击  
阅读 44

理解Nginx中Server和Location的匹配逻辑

本文主要介绍了Server和Location匹配逻辑相关内容。
上篇文章回顾:浅谈SYNPROXY

Server的匹配逻辑

Nginx在决定请求由哪个server块执行时,主要关注的是server块中的listen和server_name两个字段

listen指令

listen字段定义server响应的ip和端口,如果没有明确配置listen字段,默认监听0.0.0.0:80(root)或者0.0.0.0:8080(非root)
listen可以被配置为:

  1. 一个ip和端口的组合

  2. 一个单独的ip,默认监听80端口

  3. 一个单独的端口,默认监听所有的ip接口

  4. 一个Unix socket路径

其中最后一项通常只用于在不同的server之间传递请求
选择要使用的server的规则如下:

  1. Nginx首先将所有"不完整"的listen指令进行转换,比如没有listen字段的转换为listen 0.0.0.0:80,listen 1.1.1.1转换为listen 1.1.1.1:80等

  2. Nginx根据请求的ip和端口创建一个与请求最匹配的server块列表,优先匹配指定了特定ip的server块,其次才会选择listen 0.0.0.0的这种server块.但是无论是哪种情况,端口必须是完全匹配的

  3. 如果只有一个最佳匹配,那么将使用匹配的server块响应请求,否则开始评估每一个server块的server_name指令

再次强调一遍,只有当listen指令无法找到最佳匹配时才会考虑评估server_name指令.
比如,我们假设example.com域名指向了192.168.0.1,且位于192.168.0.1上的nginx有且仅有如下两个server块:

# server block 1server {
    listen 192.168.0.1;
    server_name other.com
    ...
}

# server block 2server {
    listen 80;
    server_name example.com
    ...
}复制代码

Server_name指令

如果根据listen指令无法得到最佳匹配,将会开始解析server_name指令.nginx会检查请求中的"Host"头,这个值包含了客户端实际试图请求的域名或者ip地址.nginx会根据这个值去匹配server_name指令,匹配规则如下:

  1. nginx会尝试寻找一个和sever_name和Host值完全匹配的server块,如果找到多个精确匹配,则会使用第一个匹配的server块

  2. 如果没有找到精确匹配的server块,则nginx尝试找到server_name带有*开头的server块,如果找到多个,则选择最长匹配的server块

  3. 如果没有找到使用开头的server块,则会寻找以结尾的server块,同样,如果有多个匹配, 选择最长匹配

  4. 如果没有找到使用*匹配的server块,则会寻找使用正则表达式(以~开头)定义server_name的server块,如果找到多个匹配,会使用第一个匹配

  5. 如果没有找到正则表达式匹配的server块,则nginx将会选择一个匹配listen字段的default server块.每一个ip和端口组合都可以配置一个且只能配置一个默认的default_server块,如果没有的话,则会选择可用列表中的第一个server(此时的选择是随机的,顺序不固定)

示例如下:

(1)准确的server_name匹配,例如:

server {
     listen       80;
     server_name  www.domain.com;
     ...
}复制代码

(2)以*通配符开始的字符串:

server {
     listen       80;
     server_name  *.domain.com;
     ...
}复制代码

(3)以*通配符结束的字符串:

server {
     listen       80;
     server_name  www.*;
     ...
}复制代码

(4)匹配正则表达式:

server {
     listen       80;
     server_name  ~^(?.+)\.domain\.com$;
     ...
}复制代码

(5)如果以上都没有匹配,则使用default_server.如果没有指定default_server,则会选择第一个可用的server.我们可以指定对于没有匹配的host值时,返回错误到客户端.可以用来防止别人把垃圾流量转到你的网站。

server {
    listen  80   default_server;
    server_name  _;    return 444;
}复制代码

通过返回444这个nginx的非标准错误码让nginx断开与浏览器的连接

Location的匹配逻辑

Location语法解析

location optional_modifier location_match {
    ...
}复制代码

其中可用的modifier修饰符如下

判定规则
  1. nginx首先检查基于前缀的location匹配(即不包含正则表达式的匹配)

  2. 如果有使用=修饰符的location块与请求的URL完全匹配,则立刻使用该location响应请求

  3. 如果没有找到带有=修饰符的location块匹配,则会继续计算非精确前缀,根据给定的URI找到最长匹配前缀,然后进行如下处理:

  4. (1)如果最长的匹配location带有^~修饰符,nginx立刻使用该location响应请求

    (2)如果最长的匹配location不带有^~修饰符,nginx会将该匹配暂时存起来,然后继续后续匹配

  5. 在确定并储存最长匹配的前缀location块后,nginx继续检查正则表达式匹配location(区分大小写/不区分大小写).如果存在正则表达式满足要求的匹配,则会选择与请求的URI匹配的第一个正则表达式的location来相应请求

  6. 如果没有找到与请求的URI匹配的正则表达式location,则使用之前存储的最长前缀location响应请求

补充

  1. 通常情况下,一旦选择使用某一个location响应请求,那么请求将会在该location内部进行处理,而与其他location无关.但是location中某些指令会触发新的location匹配,比如:

  2. (1)try_files

    (2)rewrite

    (3)error_page

  3. 关于为https配置default_server,参考Properly setting up a “default” nginx server for https

本文首发于公众号“小米运维”,点击查看原文


Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/29848
 
333 次点击