理清 nginx 中的 location 配置

简介: 理清 nginx 中的 location 配置

前言
location 指令是 nginx 中最关键的指令之一,location 指令的功能是用来匹配不同的 URI 请求,进而对请求做不同的处理和响应,这其中较难理解的是多个 location 的匹配顺序,本文会作为重点来解释和说明。

开始之前先明确一些约定,我们输入的网址叫做请求 URI,nginx 用请求 URI 与 location 中配置的 URI 做匹配。

nginx 文件结构
首先我们先简单了解 nginx 的文件结构,nginx 的 HTTP 配置主要包括三个区块,结构如下:

Global: nginx 运行相关
Events: 与用户的网络连接相关
http
http Global: 代理,缓存,日志,以及第三方模块的配置
server
server Global: 虚拟主机相关
location: 地址定向,数据缓存,应答控制,以及第三方模块的配置
从上面展示的 nginx 结构中可以看出 location 属于请求级别配置,这也是我们最常用的配置。

配置 location 块
location 语法
location 块通过指定模式来与客户端请求的 URI 相匹配。

location 基本语法:

匹配 URI 类型,有四种参数可选,当然也可以不带参数。
命名 location,用 @ 来标识,类似于定义 goto 语句块。
location [ = | ~ | ~ | ^~ ] /URI { … }
location @/name/ { … }
location 匹配命令解释
参数 解释
空 location 后没有参数直接跟着标准 URI,表示前缀匹配,代表跟请求中的 URI 从头开始匹配。
= 用于标准 URI 前,要求请求字符串与其精准匹配,成功则立即处理,nginx 停止搜索其他匹配。
^~ 用于标准 URI 前,并要求一旦匹配到就会立即处理,不再去匹配其他的那些个正则 URI,一般用来匹配目录
~ 用于正则 URI 前,表示 URI 包含正则表达式,区分大小写
~
用于正则 URI前,表示 URI 包含正则表达式,不区分大小写
@ @ 定义一个命名的 location,@ 定义的 location 名字一般用在内部定向,例如 error_page, try_files 命令中。它的功能类似于编程中的 goto。
location 匹配顺序
nginx 有两层指令来匹配请求 URI。第一个层次是 server 指令,它通过域名、ip 和端口来做第一层级匹配,当找到匹配的 server 后就进入此 server 的 location 匹配。

location 的匹配并不完全按照其在配置文件中出现的顺序来匹配,请求 URI 会按如下规则进行匹配:

先精准匹配=,精准匹配成功则会立即停止其他类型匹配;
没有精准匹配成功时,进行前缀匹配。先查找带有^~的前缀匹配,带有^~的前缀匹配成功则立即停止其他类型匹配,普通前缀匹配(不带参数^~)成功则会暂存,继续查找正则匹配;
=和^~均未匹配成功前提下,查找正则匹配~和~*。当同时有多个正则匹配时,按其在配置文件中出现的先后顺序优先匹配,命中则立即停止其他类型匹配;
所有正则匹配均未成功时,返回步骤 2 中暂存的普通前缀匹配(不带参数^~)结果。
以上规则简单总结就是优先级从高到低依次为(序号越小优先级越高):

  1. location = # 精准匹配
  2. location ^~ # 带参前缀匹配
  3. location ~ # 正则匹配(区分大小写)
  4. location ~* # 正则匹配(不区分大小写)
  5. location /a # 普通前缀匹配,优先级低于带参数前缀匹配,多个前缀匹配命中时,取较长的那个
  6. location / # 任何没有匹配成功的,都会匹配进这里处理
    上述匹配规则可以用以下伪代码表示,加深理解:

function match(uri):
rv = NULL

if uri in exact_match:
return exact_match[uri]

if uri in prefix_match:
if param of prefix_match[uri] is '^~':
return prefix_match[uri]
else:
rv = prefix_match[uri] // 注意这里没有 return,且这里是最长匹配

if uri in regex_match:
return regex_match[uri] // 按文件中顺序,找到即返回
return rv
案例分析
接下来,让我们通过一些实际案例来验证上述规则。

案例 1
server {
server_name website.com;
location /doc {
return 701; # 用这样的方式,可以方便知道请求到了哪里
}
location ~* ^/document$ {
return 702;
}
}
curl -I website.com:8080/document 返回 HTTP/1.1 702
说明:按照上述的规则,显然第二个正则匹配会有更高的优先级

案例 2
server {
server_name website.com;
location /document {
return 701;
}
location ~* ^/document$ {
return 702;
}
}
curl -I website.com:8080/document 返回 HTTP/1.1 702
说明:第二个匹配了正则表达式,优先级高于第一个普通前缀匹配

案例 3
server {
server_name website.com;
location ^~ /doc {
return 701;
}
location ~* ^/document$ {
return 702;
}
}
curl http://website.com/document 返回 HTTP/1.1 701
说明:第一个前缀匹配^~命中以后不会再搜寻正则匹配,所以会第一个命中

案例 4
server {
server_name website.com;
location /docu {
return 701;
}
location /doc {
return 702;
}
}
curl -I website.com:8080/document 会返回 HTTP/1.1 701

server {
server_name website.com;
location /doc {
return 702;
}
location /docu {
return 701;
}
}
curl -I website.com:8080/document 依然返回 HTTP/1.1 701
说明:前缀匹配下,返回最长匹配的 location,与 location 所在位置顺序无关

案例 5
server {
listen 8080;
server_name website.com;

location ~ ^/doc[a-z]+ {
    return 701;
}

location ~ ^/docu[a-z]+ {
    return 702;
}

}
curl -I website.com:8080/document 返回 HTTP/1.1 701
把顺序换一下:

server {
listen 8080;
server_name website.com;

location ~ ^/docu[a-z]+ {
    return 702;
}

location ~ ^/doc[a-z]+ {
    return 701;
}

}
curl -I website.com:8080/document 返回 HTTP/1.1 702
说明:可见正则匹配是使用文件中的顺序,先匹配成功的返回

其他 location 配置相关
匹配问号后的参数
请求 URI 中问号后面的参数是不能在 location 中匹配到的,这些参数存储在$args变量中,可以用if来判断。

例如,下面的配置匹配带有 tag 参数的 URI。

location / {
if ($args ~ tag=) {

 # 如果地址匹配到 tag=

}
}
命名 location
带有@的 location 是用来定义一个命名的 location,这种 location 不参与请求匹配,一般用在内部定向。用法如下:

location / {
try_files $uri $uri/ @custom
}
location @custom {

# ...do something

}
上例中,当尝试访问 URI 找不到对应的文件就重定向到我们自定义的命名 location(此处为 custom)。

值得注意的是,命名 location 中不能再嵌套其它的命名 location。

location 实际使用建议
所以实际使用中,个人觉得至少有三个匹配规则定义,如下:

第一个必选规则:直接匹配网站根,通过域名访问网站首页比较频繁,使用这个会加速处理,官网如是说。

[kod.hitonexpress.com)
[kod.heyf.net)
[kod.hnwxkj.com)
[kod.hebmj258.com)
[kod.hsddcz.com)
[kod.huayin116.com)
[kod.huawin.net)
[kod.hnqyjk.com)
[kod.hsrz.net)
[kod.hwave.net)
这里是直接转发给后端应用服务器了,也可以是一个静态首页:

location = / {
proxy_pass http://tomcat:8080/index
}
第二个必选规则是处理静态文件请求,这是 nginx 作为 http 服务器的强项,有两种配置模式,目录匹配或后缀匹配,任选其一或搭配使用:

location ^~ /static/ {
root /webroot/static/;
}
location ~* .(gif|jpg|jpeg|png|css|js|ico)$ {
root /webroot/res/;
}
第三个规则就是通用规则,用来转发动态请求到后端应用服务器:

location / {
proxy_pass http://tomcat:8080/
}

相关文章
|
24天前
|
弹性计算 人工智能 架构师
阿里云携手Altair共拓云上工业仿真新机遇
2024年9月12日,「2024 Altair 技术大会杭州站」成功召开,阿里云弹性计算产品运营与生态负责人何川,与Altair中国技术总监赵阳在会上联合发布了最新的“云上CAE一体机”。
阿里云携手Altair共拓云上工业仿真新机遇
|
16天前
|
存储 关系型数据库 分布式数据库
GraphRAG:基于PolarDB+通义千问+LangChain的知识图谱+大模型最佳实践
本文介绍了如何使用PolarDB、通义千问和LangChain搭建GraphRAG系统,结合知识图谱和向量检索提升问答质量。通过实例展示了单独使用向量检索和图检索的局限性,并通过图+向量联合搜索增强了问答准确性。PolarDB支持AGE图引擎和pgvector插件,实现图数据和向量数据的统一存储与检索,提升了RAG系统的性能和效果。
|
20天前
|
机器学习/深度学习 算法 大数据
【BetterBench博士】2024 “华为杯”第二十一届中国研究生数学建模竞赛 选题分析
2024“华为杯”数学建模竞赛,对ABCDEF每个题进行详细的分析,涵盖风电场功率优化、WLAN网络吞吐量、磁性元件损耗建模、地理环境问题、高速公路应急车道启用和X射线脉冲星建模等多领域问题,解析了问题类型、专业和技能的需要。
2577 22
【BetterBench博士】2024 “华为杯”第二十一届中国研究生数学建模竞赛 选题分析
|
18天前
|
人工智能 IDE 程序员
期盼已久!通义灵码 AI 程序员开启邀测,全流程开发仅用几分钟
在云栖大会上,阿里云云原生应用平台负责人丁宇宣布,「通义灵码」完成全面升级,并正式发布 AI 程序员。
|
3天前
|
JSON 自然语言处理 数据管理
阿里云百炼产品月刊【2024年9月】
阿里云百炼产品月刊【2024年9月】,涵盖本月产品和功能发布、活动,应用实践等内容,帮助您快速了解阿里云百炼产品的最新动态。
阿里云百炼产品月刊【2024年9月】
|
2天前
|
存储 人工智能 搜索推荐
数据治理,是时候打破刻板印象了
瓴羊智能数据建设与治理产品Datapin全面升级,可演进扩展的数据架构体系为企业数据治理预留发展空间,推出敏捷版用以解决企业数据量不大但需构建数据的场景问题,基于大模型打造的DataAgent更是为企业用好数据资产提供了便利。
164 2
|
20天前
|
机器学习/深度学习 算法 数据可视化
【BetterBench博士】2024年中国研究生数学建模竞赛 C题:数据驱动下磁性元件的磁芯损耗建模 问题分析、数学模型、python 代码
2024年中国研究生数学建模竞赛C题聚焦磁性元件磁芯损耗建模。题目背景介绍了电能变换技术的发展与应用,强调磁性元件在功率变换器中的重要性。磁芯损耗受多种因素影响,现有模型难以精确预测。题目要求通过数据分析建立高精度磁芯损耗模型。具体任务包括励磁波形分类、修正斯坦麦茨方程、分析影响因素、构建预测模型及优化设计条件。涉及数据预处理、特征提取、机器学习及优化算法等技术。适合电气、材料、计算机等多个专业学生参与。
1577 16
【BetterBench博士】2024年中国研究生数学建模竞赛 C题:数据驱动下磁性元件的磁芯损耗建模 问题分析、数学模型、python 代码
|
22天前
|
编解码 JSON 自然语言处理
通义千问重磅开源Qwen2.5,性能超越Llama
击败Meta,阿里Qwen2.5再登全球开源大模型王座
979 14
|
4天前
|
Linux 虚拟化 开发者
一键将CentOs的yum源更换为国内阿里yum源
一键将CentOs的yum源更换为国内阿里yum源
221 2
|
17天前
|
人工智能 开发框架 Java
重磅发布!AI 驱动的 Java 开发框架:Spring AI Alibaba
随着生成式 AI 的快速发展,基于 AI 开发框架构建 AI 应用的诉求迅速增长,涌现出了包括 LangChain、LlamaIndex 等开发框架,但大部分框架只提供了 Python 语言的实现。但这些开发框架对于国内习惯了 Spring 开发范式的 Java 开发者而言,并非十分友好和丝滑。因此,我们基于 Spring AI 发布并快速演进 Spring AI Alibaba,通过提供一种方便的 API 抽象,帮助 Java 开发者简化 AI 应用的开发。同时,提供了完整的开源配套,包括可观测、网关、消息队列、配置中心等。
735 9