共计 4037 个字符,预计需要花费 11 分钟才能阅读完成。
因为业务系统需求,需要对 web 服务作 nginx 代理,在不断的尝试过程中,简单总结了一下常见的 nginx 代理配置。
1. 最简反向代理配置
在 http 节点下,使用 upstream 配置服务地址,使用 server 的 location 配置代理映射。
upstream my_server {server 10.0.0.2:8080;
keepalive 2000;
}
server {listen 80;
server_name 10.0.0.1;
client_max_body_size 1024M;
location /my/ {proxy_pass http://my_server/;
proxy_set_header Host $host:$server_port;
}
}
通过该配置,访问 nginx 地址 http://10.0.0.1:80/my 的请求会被转发到 my_server 服务地址 http://10.0.0.2:8080/。
需要注意的是,如果按照如下配置:
upstream my_server {server 10.0.0.2:8080;
keepalive 2000;
}
server {listen 80;
server_name 10.0.0.1;
client_max_body_size 1024M;
location /my/ {proxy_pass http://my_server;
proxy_set_header Host $host:$server_port;
}
}
那么,访问 nginx 地址 http://10.0.0.1:80/my 的请求会被转发到 my_server 服务地址 http://10.0.0.2:8080/my。这是因为 proxy_pass 参数中如果不包含 url 的路径,则会将 location 的 pattern 识别的路径作为绝对路径。
2. 重定向报文代理
即便配置了 nginx 代理,当服务返回重定向报文时(http code 为 301 或 302),会将重定向的目标 url 地址放入 http response 报文的 header 的 location 字段内。用户浏览器收到重定向报文时,会解析出该字段并作跳转。此时新的请求报文将直接发送给服务地址,而非 nginx 地址。为了能让 nginx 拦截此类请求,必须修改重定向报文的 location 信息。
location /my/ {proxy_pass http://my_server;
proxy_set_header Host $host:$server_port;
proxy_redirect / /my/;
}
使用 proxy_redirect 可以修改重定向报文的 location 字段,例子中会将所有的根路径下的 url 代理到 nginx 的 /my/ 路径下返回给用户。比如服务返回的重定向报文的 location 原始值为 /login,那么经过 nginx 代理后,用户收到的报文的 location 字段为 /my/login。此时,浏览器将会跳转到 nginx 的 /my/login 地址进行访问。
需要注意的是,服务返回的重定向报文的 location 字段有时会填写绝对路径(包含服务的 ip/ 域名和端口),有时候会填写相对路径,此时需要根据实际情况进行甄别。
location /my/ {proxy_pass http://my_server;
proxy_set_header Host $host:$server_port;
proxy_redirect http://my_server/ http://$host:$server_port/my/;
}
上述配置便是将 my_server 服务的根路径下的所有路径代理到 nginx 地址的 /my/ 路径下。当 nginx 配置只有一个 server 时,http://$host:$server_port
前缀可以省略。
3. 报文数据替换
使用 nginx 代理最牛(dan)逼(sui)的情况就是 http 响应报文内写死了服务地址或 web 绝对路径。写死服务地址的情况比较少见,但也偶尔存在。最棘手的是写死了 web 绝对路径,尤其是绝对路径都没有公共前缀。举个例子来说:
一般的 web 页面会包含如下类似路径:
- /public:用于静态页面资源,如 js 脚本 /public/js,样式表 /public/css,图片 /public/img 等。
- /static:和 /public 类似。
- /api:用于后台服务 API 接口。
- /login:用于登录验证。
- 其他。
对于这样的服务,可能的代理配置如下:
location /my/ {proxy_pass http://my_server/;
proxy_set_header Host $host:$server_port;
proxy_redirect / /my/;
}
location /login/ {proxy_pass http://my_server/public;
proxy_set_header Host $host:$server_port;
}
location /public/ {proxy_pass http://my_server/public;
proxy_set_header Host $host:$server_port;
}
location /api/ {proxy_pass http://my_server/api;
proxy_set_header Host $host:$server_port;
}
由于 web 页面或静态资源内写死了类似的绝对路径,那么对于用户来说,通过页面内的链接进行跳转时,都会请求到 nginx 服务对应的路径上。一旦存在另一个服务也包含类似的路径,也需要 nginx 进行代理,那么矛盾就出现了:访问 nginx 的同一个路径下的请求究竟转发给哪一个服务?
要解决这个问题,必须在用户收到报文前,将报文的数据中包含的绝对路径都添加统一的前缀,如 /my/public,/my/api,/my/login,这样 nginx 代理配置则可以简化为:
location /my/ {proxy_pass http://my_server/;
proxy_set_header Host $host:$server_port;
proxy_redirect / /my/;
}
location /other/ {proxy_pass http://other_server/;
proxy_set_header Host $host:$server_port;
proxy_redirect / /other/;
}
nginx 的 ngx_http_sub_module 模块提供了类似的报文数据替换功能,该模块默认不会安装,需要在编译 nginx 时添加 –with-http_sub_module 参数,或者直接下载 nginx 的 rpm 包。
使用 sub_filter 对数据包进行替换的语法如下:
location /my/ {proxy_pass http://my_server/;
proxy_set_header Host $host:$server_port;
sub_filter 'href="https://www.linuxidc.com/' 'href="https://www.linuxidc.com/my/';
sub_filter 'src="https://www.linuxidc.com/' 'src="https://www.linuxidc.com/my/';
sub_filter_types text/html;
sub_filter_once off;
}
上述配置会将 /my/ 下的所有响应报文内容的 href=”https://www.linuxidc.com/ 替换为 href=”/my,以及 src=”https://www.linuxidc.com/ 替换为 src=”/my,即为所有的绝对路径添加公共前缀。
注意,如果需要配置多个 sub_filter,必须保证 nginx 是 1.9.4 版本之上的。
4. 总结
即便如此,sub_filter 也不能解决所有问题。目前流行的 js 框架都会有自动渲染 url 的功能,也就是说,很多绝对路径并非写死在静态页面内,也是由 js 代码框架动态生成的,面对这样的情况,sub_filter 也是无能为力了。对于这样的情况,笔者只能由衷地奉劝,还是安静的改代码吧!
更多 Nginx 相关教程见以下内容:
CentOS 6.2 实战部署 Nginx+MySQL+PHP http://www.linuxidc.com/Linux/2013-09/90020.htm
使用 Nginx 搭建 WEB 服务器 http://www.linuxidc.com/Linux/2013-09/89768.htm
搭建基于 Linux6.3+Nginx1.2+PHP5+MySQL5.5 的 Web 服务器全过程 http://www.linuxidc.com/Linux/2013-09/89692.htm
CentOS 6.3 下 Nginx 性能调优 http://www.linuxidc.com/Linux/2013-09/89656.htm
CentOS 6.3 下配置 Nginx 加载 ngx_pagespeed 模块 http://www.linuxidc.com/Linux/2013-09/89657.htm
CentOS 6.4 安装配置 Nginx+Pcre+php-fpm http://www.linuxidc.com/Linux/2013-08/88984.htm
Nginx 安装配置使用详细笔记 http://www.linuxidc.com/Linux/2014-07/104499.htm
Nginx 日志过滤 使��ngx_log_if 不记录特定日志 http://www.linuxidc.com/Linux/2014-07/104686.htm
Nginx 的详细介绍:请点这里
Nginx 的下载地址:请点这里
本文永久更新链接地址:http://www.linuxidc.com/Linux/2016-07/133119.htm