nginx使用
Nginx(发音为 “engine-x”)是一个高性能、轻量级的HTTP和反向代理服务器,同时也支持IMAP/POP3/SMTP协议。它被广泛应用于各种Web服务场景中,以下是Nginx的主要功能:
一、重写和路由
提供灵活的URL重写和路由功能,允许根据正则表达式或者其他条件进行URL转换和内部跳转。
server {
location /old-path {
rewrite ^/old-path/(.*)$ /new-path/$1 permanent; # URL永久重写
}
}
server {
location / {
if ($request_uri ~ ^/api/v1(.*)$) {
proxy_pass http://api-backend/$1; # 路由特定路径到后端API服务器
}
}
}
1、location必须以/开头吗?
在Nginx的location指令中,路径确实必须以斜杠 / 开头,除非使用的是正则表达式匹配(如 location ~ pattern { … })。对于前缀匹配和等值匹配(即 location /path { … } 和 location = /path { … }),路径都必须以斜杠开头。
2、location匹配规则
#错误,必须以/开头或使用正则表达式匹配
location api {
……
}
#nginx会自上而下扫描全部location,找到最佳匹配才执行
#例如:http://localhost/api会匹配到location /api/ {}而不是location /api {}
location /api {
#http://localhost/flh/api/ 匹配不到“/”代表从uri的根开始匹配,http://localhost/flh/api/的uri是“/flh/api/”
#http://localhost/apiflh 能匹配到
#http://localhost/api/flh 能匹配到
……
}
location /api/ {
#http://localhost/flh/api/ 匹配不到“/”代表从uri的根开始匹配,http://localhost/flh/api/的uri是“/flh/api/”
#http://localhost/apiflh 匹配不到
#http://localhost/api/flh 能匹配到
#建议使用本格式
……
}
3、rewrite和proxy_pass的区别
rewrite 和 proxy_pass 是 Nginx 中用于处理请求的两个不同指令,它们有着不同的功能和作用:
rewrite:
-
功能:rewrite 指令用于在 Nginx 内部重写 URI(统一资源标识符),它可以在服务器或 location 块中使用。
-
用法:通过正则表达式匹配当前请求的 URI,并将其替换为新的 URI。这可以用来改变请求路径,比如重定向、清理 URL 等。
-
示例:
server { location /old-path { rewrite ^/old-path/(.*)$ /new-path/$1 permanent; # URL永久重写 } }
上述规则会将所有以 /old-path 开始的请求重写为 /new-path 加上原来路径剩余部分。
proxy_pass:
-
功能:proxy_pass 指令用于将客户端的请求转发到一个上游服务器,即实现反向代理的功能。当Nginx接收到请求时,它不会自己处理请求,而是将请求转发给后端服务如Tomcat、Node.js应用或其他HTTP服务器等。
-
用法:配置 proxy_pass 指令时,通常会指定一个代理服务器的地址和端口,也可以包含一个URI路径,该路径会被附加到代理服务器地址之后。
-
示例:
location /api { proxy_pass http://backend-server:8080/api; # 其他相关的代理设置,如header传递等 }
这样,所有对 /api 的请求都会被转发到 http://backend-server:8080/api 处理。
总结起来,rewrite 更像是在本地处理请求并修改其路径,而 proxy_pass 则是将请求整体转交给其他服务器去处理。在动静分离的场景下,rewrite 可能用于调整静态资源路径,而 proxy_pass 则负责将动态请求转发至后端应用服务器。两者常配合使用,共同实现复杂的路由策略。
4、rewrite中关键字last、break、permanent、redirect的区别
- last(不加关键字,行为类似last)
- 当rewrite指令使用了last修饰符时,当前的重写规则执行完毕后,Nginx会立即停止在当前location块内的所有后续规则的处理。
- 然后,Nginx会根据已重写后的URL重新匹配新的location块,并开始执行新匹配到的location块中的配置指令。
- 如果没有找到新的location块匹配,则通常会执行该server或默认server的配置。
- break
- 当rewrite指令使用了break修饰符时,当前的重写规则执行完毕后,Nginx将终止当前rewrite循环,即不再继续尝试匹配当前location块内剩余的rewrite规则。
- 但与last不同的是,break并不会导致重新匹配新的location块,而是继续执行当前location块内的非rewrite指令(如proxy_pass、access_log等)。
- permanent
- 执行重写:当请求的URI与带有permanent修饰符的rewrite指令规则相匹配时,Nginx会按照规则重写URI,并记录下新的URI。
- 发送重定向响应:不同于last和break,permanent修饰符会立即向客户端发送一个HTTP状态码为301的响应头,指示客户端未来应使用新的URI进行访问。此响应头包含已重写后的URI作为Location字段的值。
- 停止处理:当permanent生效时,Nginx不会继续执行当前location块内的其他任何rewrite规则,也不会执行像proxy_pass、try_files等后续指令。它会立即终止对该请求的进一步处理,并返回重定向响应给客户端。
- redirect
- 发送HTTP 302临时重定向响应,同时终止对当前请求的进一步处理。
- redirect和permanent的区别
- 都会导致浏览器地址栏变更为新URL。
- 302临时重定向在一段时间内,搜索引擎可能会同时索引旧URL和新URL,但最终会将权重转移到新URL上。301永久重定向搜索引擎会索引新URL。
5、proxy_pass匹配规则
#假设有4个nginx配置如下,现有一个请求http://localhost:80/api/flh,请问转发后的地址分别是什么?
server {
listen 80;
location /api/ {
proxy_pass http://192.168.1.100:8080;
#http://192.168.1.100:8080/api/flh
}
}
server {
listen 80;
location /api/ {
proxy_pass http://192.168.1.100:8080/;
#http://192.168.1.100:8080/flh
}
}
server {
listen 80;
location /api/ {
proxy_pass http://192.168.1.100:8080/test;
#原请求http://localhost:80/api/flh
#转发后http://192.168.1.100:8080/testflh
}
}
server {
listen 80;
location /api/ {
proxy_pass http://192.168.1.100:8080/test/;
#http://192.168.1.100:8080/test/flh
}
}
6、nginx配置路径使用/还是\
- 在URL路径和Web服务器配置(如Nginx)中,斜杠 / 是作为路径分隔符使用的,并且始终是统一的,无论使用的是哪种操作系统。
- 在Windows系统下,本地文件路径通常使用反斜杠 \ 作为路径分隔符,例如:C:\Users\username\Desktop\file.txt。但在编程语言中直接写入字符串时,由于\在大多数编程语言中具有转义字符的含义,所以通常会采用双反斜杠 \ 或者单个正斜杠 / 来表示路径,现代Windows系统通常也接受正斜杠 / 作为路径分隔符。
- 在类Unix系统下,包括Linux和macOS,本地文件路径使用正斜杠 / 作为路径分隔符,例如:/home/username/Desktop/file.txt。
- 由于Nginx会自动处理路径中的反斜杠,所以即使在Windows系统中也可以直接使用正斜杠/。例如:root c:/web/content;
二、反向代理
Nginx最常用于设置反向代理,它可以接受客户端请求,并根据配置规则将这些请求透明地转发给后端的一组服务器。通过这种方式,可以实现负载均衡,隐藏真实的服务器IP地址,以及提供统一入口点等功能。
实现
server {
listen 80;
# 这个location块匹配所有的根路径(/)请求
location / {
# proxy_pass指令用于指定将请求转发到的目标地址,可以是IP:port形式或者域名形式
# 例如:proxy_pass http://192.168.1.100:8080/;
proxy_pass http://ip:port/;
# 设置代理时传递给后端服务器的Host头部信息,保持与原始请求一致
proxy_set_header Host $host;
# 设置X-Real-IP头部信息,将客户端的真实IP地址传递给后端服务器
proxy_set_header X-Real-IP $remote_addr;
# 可能还需要添加其他有用的头部信息,例如:
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
1、配置代理时必须配置proxy_set_header吗?
proxy_set_header在Nginx反向代理配置中并非必须的,但是通常情况下建议设置这些头部信息以确保正确处理请求和响应。
-
proxy_set_header Host $host;
这个设置通常是必要的,因为许多Web应用程序依赖于Host头来确定请求的目的地(例如,在负载均衡或虚拟主机场景中)。将$host传递给后端服务器有助于保持原始请求中的主机名信息不变,这对于某些服务器来说是至关重要的。
-
proxy_set_header X-Real-IP $remote_addr;
这个设置用于将客户端的真实IP地址传递给后端服务器。因为在反向代理的情况下,后端服务器接收到的请求源IP将是代理服务器的IP而非客户端的真实IP。如果您的后端应用需要根据客户端真实IP进行访问控制、日志记录等操作,那么这个设置就是必需的。
-
其他如X-Forwarded-For等头部信息也常被用于记录客户端IP链路以及识别经过了哪些代理服务器
总之,是否配置proxy_set_header取决于您的具体需求和后端服务如何处理这些头部信息。但在实际部署中,为了保证前后端交互的正常进行,通常建议按需配置这些头部字段。
2、是否可以配置多个监听端口?
Nginx可以配置多个监听端口以处理来自不同端口的请求。每个监听端口可以对应不同的服务或配置规则。以下是一个配置多个监听端口的示例:
# 在http块内配置多个server块来监听不同的端口
http {
# 第一个server块,监听80端口
server {
listen 80;
# 配置默认站点根目录
root /var/www/html/default;
# 其他location和设置...
}
# 第二个server块,监听8080端口
server {
listen 8080;
# 配置特定站点的根目录
root /var/www/html/secondary;
# 可能会有不同的location规则和其他配置...
}
# 更多server块,监听其他端口
server {
listen 443 ssl; # 同时监听443端口并启用SSL加密
server_name example.com;
# SSL证书配置
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
# 此服务器的特定配置
...
}
}
3、正向代理和反向代理的区别
正向代理(Forward Proxy)
- 角色:站在客户端一侧,作为客户端访问外部网络的“中介”。
- 工作方式:客户端配置代理服务器地址后,通过它去访问目标网站。目标网站看到的请求来源是代理服务器而非直接来自客户端。
- 应用场景:企业内部网络过滤、隐藏客户端真实IP、突破地域限制等。
反向代理(Reverse Proxy)
- 角色:站在服务端一侧,对外界而言,它是服务的“门面”或“入口”。
- 工作方式:客户端无需知道后端服务器的具体信息,直接向反向代理服务器发送请求。反向代理根据规则将请求转发给内部网络中的实际服务器处理,并返回结果给客户端。
- 应用场景:负载均衡(分发请求到多台服务器)、安全防护(隐藏内部服务器信息和提供统一的安全策略)、缓存加速(减少对后端服务器的压力)、内容过滤与重写等。
三、负载均衡
作为反向代理的一部分,Nginx可以根据多种策略(例如轮询、权重分配、最少连接数等)在多个后端服务器之间分发流量,从而实现高可用性和性能优化。
负载均衡策略
-
轮询(Round Robin):
默认策略,将请求均匀地分配给后端服务器列表中的每一台服务器。http { upstream backend { server server1_ip:port; server server2_ip:port; # 可以添加更多服务器... } server { listen 80; location / { proxy_pass http://backend; # 其他必要的代理设置... } } }
-
加权轮询(Weighted Round Robin):
每个服务器可以被分配一个权重值,权重高的服务器将得到更多的请求。http { upstream backend { server server1_ip:port weight=3; # 该服务器权重为3 server server2_ip:port weight=1; # 该服务器权重为1 } server { listen 80; location / { proxy_pass http://backend; # 其他必要的代理设置... } } }
-
最少连接数(Least Connections):
将新的请求发送到当前活跃连接数最少的后端服务器上。http { upstream backend { least_conn; server server1_ip:port; server server2_ip:port; } server { listen 80; location / { proxy_pass http://backend; # 其他必要的代理设置... } } }
-
IP哈希(ip_hash):
根据客户端IP地址的散列结果来决定请求转发到哪个后端服务器,实现会话持久化。http { upstream backend { ip_hash; server server1_ip:port; server server2_ip:port; } server { listen 80; location / { proxy_pass http://backend; # 其他必要的代理设置... } } }
-
基于HTTP头或cookie的会话粘滞(sticky session):
通过设置特定的HTTP头部或者使用cookie来维持用户会话与特定后端服务器之间的关联。首先,你需要安装 nginx-sticky-module-ng 模块。然后在配置文件中加入如下内容:
http { upstream backend { server server1_ip:port; server server2_ip:port; # 可添加更多服务器... } server { listen 80; location / { sticky cookie srv_id expires=1h domain=.yourdomain.com; proxy_pass http://backend; # 其他必要的代理设置... } } }
这个配置会在客户端设置一个名为 srv_id 的cookie,根据该cookie的值将请求转发到同一台后端服务器上。
-
Fair(第三方模块提供):
根据后端服务器的响应时间动态调整权重,将请求分发给响应时间最短的服务器,需要安装nginx-upstream-fair模块。由于实际应用中可能存在兼容性和稳定性问题,请谨慎考虑是否采用此方法,并查阅相关文档进行配置。
nginx可以应付什么量级的负载均衡?
Nginx作为一款高性能的HTTP和反向代理服务器,其负载均衡能力可以应付非常高量级的流量。具体能应对多少量级取决于多个因素:
- 硬件资源:服务器的CPU、内存、网络带宽等硬件配置直接影响Nginx处理请求的能力。
- 配置优化:合理配置Nginx的工作模式、连接数限制、缓存策略、SSL会话复用等参数,可以显著提升性能。
- 并发连接数:Nginx通过高效的事件驱动模型(如epoll或kqueue)能够支持高并发连接,理论上可以达到数十万甚至上百万级别的并发连接数。
- 后端集群规模:通过增加更多的后端服务器并配合合理的负载均衡策略,Nginx可以将流量分散到多台机器上,实现水平扩展以应对大规模访问。
- 负载均衡策略:不同的负载均衡策略对系统性能的影响也不同,比如轮询、最少连接数、权重分配等,正确选择和配置合适的策略有助于提高整体系统的承载能力。
- 健康检查与故障恢复:有效的健康检查机制能够确保只有健康的后端服务器参与到服务中,降低因单点故障导致的整体性能下降。
在实际生产环境中,Nginx被广泛应用于大型网站、云计算平台和其他需要高可用性及大流量处理的场景,支撑TB级别甚至PB级别的数据流量。然而,具体的承受能力需要根据实际情况进行测试和调整,并随着技术更新和硬件升级而不断提升。
四、动静分离
Nginx能够很好地处理静态内容(如HTML、CSS、JavaScript文件、图片等),并将其与动态内容请求分开。静态资源直接由Nginx服务器响应,动态请求则转发到应用服务器(如PHP-FPM或Java应用服务器)。
http {
server {
listen 80;
# 静态文件处理1
location /static/ {
root /var/www/static; # 设置静态文件目录
expires 30d; # 设置浏览器缓存过期时间,可选
try_files $uri $uri/ =404; # 当请求的资源不存在时返回404错误
}
# 静态资源处理2 - 将请求映射到服务器的特定目录下
location /static/ { # 对以'/static/'开头的URL请求进行匹配
alias /var/www/static/; # 'alias'指令指定实际存储静态文件的服务器绝对路径
expires 1d; # 设置浏览器缓存过期时间为1天,有助于减少带宽和服务器负载
}
# 动态请求转发到后端服务器
location /api/ {
proxy_pass http://localhost:8080/api; # 转发至本地8080端口的后端服务
proxy_set_header Host $host; # 传递主机头信息
proxy_set_header X-Real-IP $remote_addr; # 传递客户端真实IP地址
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 传递经过代理的客户端IP地址
}
# 如果希望将所有非静态资源的请求都视为动态请求
#(location满足最佳匹配原则,当用户请求 /static/image.jpg时,会匹配到location /static/ {})
location / {
proxy_pass http://localhost:8080; # 将其他所有非静态资源请求转发至后端服务
# 同样可以设置相关的proxy_set_header以传递客户端信息
}
}
}
alias和root的区别
在Nginx实现动静分离时,root和alias都可以用来指定静态文件的路径。它们的主要区别在于处理请求URI的方式不同。
root指令:定义一个基本目录,然后将请求URI附加到这个基本目录后面来定位资源。例如:
location /static/ {
root /var/www;
}
当用户请求 /static/image.jpg 时,Nginx会查找 /var/www/static/image.jpg。
alias指令:用于映射URL到特定的目录,它会替换匹配的location部分而不是附加到基础路径上。例如:
location /static/ {
alias /var/www/static-files/;
}
当用户请求 /static/image.jpg 时,Nginx会查找 /var/www/static-files/image.jpg,而不是 /var/www/static-files/static/image.jpg。
在实际应用中,选择root还是alias取决于你的需求和目录结构。对于动静分离,通常情况下两者都可用于静态资源服务,但当需要精确控制请求URI映射到文件系统路径而不进行额外拼接时,使用alias更为合适。不过,在多数简单场景下,root指令已经足够满足需求,并且其用法更直观易理解
五、缓存加速
Nginx提供了强大的缓存功能,能够缓存来自后端服务器的静态内容,减少对后端服务器的压力,同时加快对频繁访问内容的响应速度。
在Nginx中,可以通过配置FastCGI缓存或HTTP缓存来实现对动态或静态内容的缓存加速。这里分别给出两个示例:
1、使用HTTP缓存(适用于静态内容)
http {
proxy_cache_path /var/cache/nginx/static_cache levels=1:2 keys_zone=my_http_cache:10m inactive=1d;
server {
listen 80;
location /static/ {
alias /var/www/example.com/static/;
# HTTP缓存配置
expires 1d; # 设置资源过期时间为一天
add_header Cache-Control public; # 允许所有中间代理缓存
proxy_cache my_http_cache; # 使用上面定义的缓存区域
proxy_cache_bypass $http_pragma; # 如果请求包含Pragma:no-cache,则绕过缓存
proxy_cache_revalidate on; # 在缓存有效期内尝试验证缓存是否仍然有效
proxy_cache_min_uses 1; # 在至少被使用一次后才开始缓存
proxy_cache_lock on; # 当多个请求同时到达时,只有第一个请求会获取新数据,其他请求等待并使用同一个缓存版本
add_header X-Cache-Status $upstream_cache_status; # 添加缓存状态头
# 其他静态文件处理相关配置
}
}
}
2、使用FastCGI缓存(适用于PHP等动态内容)
http {
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=my_fastcgi_cache:10m inactive=60m;
server {
listen 80;
location ~ \.php$ {
root /var/www/example.com;
fastcgi_pass unix:/run/php/php7.4-fpm.sock;
include fastcgi_params;
# FastCGI缓存配置
proxy_cache my_fastcgi_cache; # 使用上面定义的缓存区域
proxy_cache_key "$scheme$request_method$host$request_uri"; # 缓存键生成规则
proxy_cache_valid 200 302 60m; # 对于200和302响应码,缓存60分钟
proxy_cache_methods GET HEAD; # 只缓存GET和HEAD请求
add_header X-Cache-Status $upstream_cache_status; # 添加缓存状态头
# 其他FastCGI相关配置
}
}
}
六、SSL终止(即HTTPS解密)
Nginx可作为HTTPS请求的前端处理器,处理SSL/TLS加密解密,减轻后端服务器的加密计算负担,并且支持证书管理、SSL会话缓存等功能。
http {
# 定义服务器监听HTTPS端口并启用SSL模块
server {
listen 443 ssl;
server_name yourdomain.com; # 替换为你的域名
# SSL证书文件路径设置
ssl_certificate /path/to/your/server.crt; # 服务器证书文件
ssl_certificate_key /path/to/your/server.key; # 私钥文件
# SSL相关配置选项,可根据需要调整
ssl_protocols TLSv1.2 TLSv1.3; # 支持的TLS协议版本
ssl_ciphers HIGH:!aNULL:!MD5; # 安全加密套件列表
ssl_prefer_server_ciphers on; # 优先使用服务器指定的加密套件
ssl_session_cache shared:SSL:10m; # SSL会话缓存大小和类型
ssl_session_timeout 1d; # SSL会话超时时间
# 解密客户端请求后,将HTTP请求转发至后端服务器
location / {
proxy_pass http://backend-server:8080; # 替换为你的后端服务器地址与端口
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https; # 传递原始协议信息给后端
}
}
}
在这个示例中,Nginx监听443端口以接收HTTPS请求,并通过提供的服务器证书和私钥对客户端的SSL连接进行终止。然后,它将解密后的HTTP请求代理到后端服务器上。后端服务器无需处理SSL/TLS握手过程,只需处理普通的HTTP请求即可。
请确保替换上述配置中的yourdomain.com、/path/to/your/server.crt 和 /path/to/your/server.key 为你实际的域名和证书文件路径。同时,根据你的后端服务配置,正确设置 proxy_pass 指令指向的实际地址。
七、虚拟主机
支持多站点管理,基于域名或者IP来区分不同的网站,一个Nginx实例可以配置多个虚拟主机。
server {
listen 80;
server_name example1.com;
root /var/www/example1;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
server {
listen 80;
server_name example2.com;
root /var/www/example2;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
当请求的域名是example1.com或www.example1.com时,请求将被第一个server块处理;
当请求的域名是example2.com或www.example2.com时,请求将被第二个server块处理;
如果没有任何server_name匹配请求的域名,那么Nginx将使用第一个server块作为默认匹配项。
八、限速和保护
可以配置速率限制,防止DDoS攻击和其他恶意活动;同时支持基本认证、IP黑名单、白名单等多种安全措施。
limit_req_zone $binary_remote_addr zone=req_limit:10m rate=1r/s; # 定义速率限制区域
server {
location / {
limit_req zone=req_limit burst=5 nodelay; # 每秒不超过1个请求,突发允许5个
}
}
server {
auth_basic "Restricted Area";
auth_basic_user_file /etc/nginx/.htpasswd; # 基本身份验证
location / {
# ...
}
}
九、健康检查
Nginx可以定期检查后端服务器的健康状况,并自动从负载均衡池中移除不健康的服务器。
upstream backend {
server backend1.example.com;
server backend2.example.com;
keepalive 64;
check interval=3000 rise=2 fall=5 timeout=1000; # Nginx Plus支持健康检查
}
十、实际解决问题示例
1、转发页面请求(A平台调用B的页面)
请求流程:
- A平台发起请求http://ip1:port1/rhm3/hismzzj.htm
- nginx重定向并把浏览器地址栏更新为http://ip1:port1/rhm-configure/page/his/mzzj,然后nginx把请求转发到B地址http://ip2:port2/rhm-configure/page/his/mzzj
- B返回html页面,页面中引入需要的js,css;(此处html引入js、css等资源使用的是相对路径)
- js中请求rhm5的页面作为子页面嵌入B返回的页面中
#必须使用重定向并加上permanent强制把浏览器地址栏地址改变为http://ip1:port1/rhm-configure/page/his/mzzj
location /hismzzj.htm {
rewrite ^/hismzzj.htm$ /rhm-configure/page/his/mzzj permanent;
}
#然后走 /rhm-configure代理转发到http://ip2:port2/rhm-configure/page/his/mzzj;
#此时B返回html页面中引入js的写法是<script src="../../js/jquery-3.6.1.js"></script>
#html的位置http://ip1:port1/rhm-configure/his/mzzj.html,则获取js的地址是http://ip:port/rhm-configure/js/jquery-3.6.1.js正好命中位置
location /rhm-configure {
proxy_pass http://ip2:port2/rhm-configure;
}
#如果只是用proxy_pass完成转发,此时浏览器地址还是http://ip1:port1/rhm3/hismzzj.htm
#请求js的地址是http://ip1:port1/js/jquery-3.6.1.js,路径错误,此处js只是举例用,还有其它类似路径的请求
location /rhm3/hismzzj.htm {
proxy_pass http://ip2:port2/rhm-configure/page/his/mzzj;
}
#js中请求rhm5的页面作为子页面嵌入B返回的页面中,请求http://ip1:port1/rhm5代理到http://ip2:port2/rhm5
location /rhm5 {
proxy_pass http://ip2:port2;
}
2、根据自定义请求头的值转发到不同服务器的接口
#写法1
server {
listen 80;
server_name localhost;
#下载数据转发代理
location /piduhongguang/downloaddata {
set $flag 0;
#if语句不支持“||” “&&”
if ($http_m_type = 'UPDATE_ORGANIZATION') {
set $flag 1;
}
if ($http_m_type = 'UPDATE_PERSONNEL') {
set $flag 1;
}
if ($http_m_type = 'PHS_RECORD') {
set $flag 1;
}
#把代理分成转发和重定向两部分实现是因为,在if语句中proxy_pass后不允许配置uri
if ($flag = 0) {
#没有匹配到,跳转到A
rewrite ^/(.*)$ /fmd/user/downLoadInfoPtSanLian break;
proxy_pass http://ip1:port1;
}
if ($flag = 1) {
#匹配到,跳转到B
rewrite ^/(.*)$ /rhmful/api/v2/pidu/basedata/syncData break;
proxy_pass http://ip2:port2;
}
}
}
#写法2
server {
listen 80;
server_name localhost;
#下载数据转发代理
location /piduhongguang/downloaddata {
//默认A地址
set $target_url 'http://ip1:port1/fmd/user/downLoadInfoPtSanLian';
#匹配到,跳转到B
#if语句不支持“||” “&&”
if ($http_m_type = 'UPDATE_ORGANIZATION') {
set $target_url 'http://ip2:port2/rhmful/api/v2/pidu/basedata/syncData';
}
if ($http_m_type = 'UPDATE_PERSONNEL') {
set $target_url 'http://ip2:port2/rhmful/api/v2/pidu/basedata/syncData';
}
if ($http_m_type = 'PHS_RECORD') {
set $target_url 'http://ip2:port2/rhmful/api/v2/pidu/basedata/syncData';
}
#proxy_pass后使用自定义变量时,$target_url不可使用localhost(用127.0.0.1代替),很多默认处理会失效
proxy_pass $target_url;
}
}
当客户端发起一个到localhost/piduhongguang/downloaddata的HTTP请求时:
-
首先设置变量$flag为0。
-
检查请求头中的$http_m_type字段,如果它的值等于 ‘UPDATE_ORGANIZATION’、‘UPDATE_PERSONNEL’ 或 PHS_RECORD’ 中的任何一个,则将 $flag 设置为 1。
-
根据 $flag 的值来决定如何处理请求:
- 如果 $flag 为 0,表示请求头中没有匹配到预设的类型之一,此时通过 rewrite 规则将请求重定向至 /fmd/user/downLoadInfoPtSanLian 路径,并使用 break 结束当前重写阶段。然后通过 proxy_pass 将修改后的请求代理到本地8090端口的服务上。http://ip1:port1/fmd/user/downLoadInfoPtSanLian
- 如果 f l a g 为 1 ,意味着请求头中的 flag 为 1,意味着请求头中的 flag为1,意味着请求头中的http_m_type匹配到了预设类型,这时同样通过 rewrite 规则将请求重定向至 /rhmful/api/v2/pidu/basedata/syncData 路径,并用 break 结束重写阶段。最后依然通过 proxy_pass 将请求转发给本地8090端口的同一个服务。http://http://ip2:8port2/rhmful/api/v2/pidu/basedata/syncData
总结:这个配置根据HTTP请求头中的特定字段值($http_m_type)来决定请求应被转发至后端服务的哪个具体接口,实现了基于请求内容动态路由的功能。
优化
在Nginx中,处理rewrite和proxy_pass的方式是基于事件循环而非逐行执行。if语句和rewrite指令的使用存在一定的限制和复杂性。nginx官方文档强烈建议避免在if语句中使用proxy_pass,并且尽量减少对if语句的依赖,因为它们可能会导致意想不到的结果和性能问题。
为了解决这个问题,可以考虑采用其他方法,例如使用变量结合单个rewrite规则和一个统一的proxy_pass:
http {
#map只能写在http中不能写在server或location中
map $http_m_type $target_path {
UPDATE_ORGANIZATION 'http://ip1:port1/rhmful/api/v2/pidu/basedata/syncData';
UPDATE_PERSONNEL 'http://ip1:port1/rhmful/api/v2/pidu/basedata/syncData';
PHS_RECORD 'http://ip1:port1/rhmful/api/v2/pidu/basedata/syncData';
default 'http://ip2:port2/fmd/user/downLoadInfoPtSanLian';
}
server {
listen 80;
server_name localhost;
location /piduhongguang/downloaddata {
proxy_pass $target_path;
}
}
}