Nginx分布式框架详解80-85反向代理01
Nginx 如何变成一个代理服务器?Nginx 又如何将客户端的请求转发给其他的服务器?本内容将学习 Nginx 的反向代理知识。
反向代理概述
正向代理代理的对象是客户端,反向代理代理的对象是服务端,这是两者之间最大的区别。
nginx既可以实现正向代理,也可以实现反向代理。
我们先来通过一个小案例演示下 Nginx 正向代理的简单应用。
正向代理
- 服务端的设置
http {
# 配置请求处理日志格式
log_format main 'client send request Client-IP=$remote_addr ServerIP=$host';
server {
listen 80;
server_name mayanan.cn;
access_log logs/access.log main;
location / {
root html;
index index.html;
}
}
}
- 使用客户端访问服务端:http://192.168.200.133,打开日志查看结果
client send request Client-IP=114.245.203.80 ServerIP=mayanan.cn
- 代理服务器设置
server {
listen 80;
server_name flask-test.mayanan.cn;
access_log logs/access.log main;
location / {
proxy_pass http://mayanan.cn;
}
}
- 设置完成后,再次通过浏览器访问服务端
client send request Client-IP=123.57.142.92 ServerIP=mayanan.cn
client send request Client-IP=114.245.203.80 ServerIP=flask-test.mayanan.cn
通过对比,上下两次的日志记录,会发现虽然我们是客户端访问服务端,但是使用了代理,那么服务端能看到的只是代理发送过去的请求,这样就使用 Nginx 实现了正向代理的设置。
但是 Nginx 正向代理,在实际的应用中不是特别多,所以我们简单了解下,接下来我们继续学习 Nginx 的反向代理,这是 Nginx 比较重要的一个功能。
nginx反向代理之proxy_pass指令
反向代理语法配置
Nginx 反向代理模块的指令是由 ngx_http_proxy_module 模块进行解析,该模块在安装 Nginx 的时候已经自动加载到 Nginx 中了,接下来我们把反向代理中的常用指令一一介绍下:
- proxy_pass: 配置代理的服务器地址
- proxy_set_header: 转发给被代理服务器时,设置一些请求头信息
- proxy_redirect: 防止客户端可以看到被代理服务器的地址
proxy_pass
该指令用来设置被代理服务器地址,可以是主机名称、IP 地址加端口号形式,没有默认值。
语法 | 默认值 | 位置 |
---|---|---|
proxy_pass |
— | location |
URL
为要设置的被代理服务器地址,包含传输协议(http、https://)、主机名称或 IP 地址加端口号、URI 等要素。
例如:
# 例子
server {
listen 80;
server_name flask-test.mayanan.cn;
access_log logs/access.log main;
location /server {
proxy_pass http://mayanan.cn; // 不加斜线访问的是:http://mayanan.cn/server/index.html
}
location /server {
proxy_pass http://mayanan.cn/; // 加斜线访问的是:http://mayanan.cn/index.html
}
}
在编写 proxy_pass 的时候,后面的值要不要加 /?
来看一个具体的例子来决定proxy_pass后面到底要不要加 /
server {
listen 80;
server_name localhost;
location / {
# 下面两个地址加不加斜杠,效果都一样,因为 location 后的 / 会添加在代理地址后面
proxy_pass http://192.168.200.146;
proxy_pass http://192.168.200.146/;
}
}
server{
listen 80;
server_name localhost;
location /server {
# 下面两个地址必须加斜杠,因为 location 后的 /server 会添加在代理地址后面,第一个将没有 / 结尾
#proxy_pass http://192.168.200.146;
proxy_pass http://192.168.200.146/;
}
}
# 上面的 location:当客户端访问 http://localhost/server/index.html
# 第一个 proxy_pass 就变成了 http://localhost/server/index.html
# 第二个 proxy_pass 就变成了 http://localhost/index.html 效果就不一样了。
第一个 location(第 4 行代码):当客户端访问 http://localhost/index.html,两个 proxy_pass 效果是一样的,因为 location 后的 / 会添加在代理地址后面,所以有没有 /,效果都一样。
第一个 location(第 14 行代码):当客户端访问 http://localhost/server/index.html,这个时候,第一个 proxy_pass 就变成了 http://192.168.200.146/server/index.html,第二个 proxy_pass 就变成了 http://192.168.200.146/index.html 效果就不一样了
如果不以 / 结尾,则 location 后的 /server 会添加在地址后面,所以第一个 proxy_pass 因为没有 / 结尾而被加上 /server,而第二个自带了 / ,所以不会添加 /server。
上面的例子仅仅针对:访问任意请求如 /server 时,想要代理到其他服务器的首页,则加 /,否则你如果真的想访问 /server 下的资源,那么不要加 /。
所以加了 / 后,请求的是服务器根目录下的资源。
反向代理之proxy_set_header指令
该指令可以更改 Nginx 服务器接收到的客户端请求的请求头信息,然后将新的请求头发送给代理的服务器。默认值是发送代理服务器的地址和 close。
语法 | 默认值 | 位置 |
---|---|---|
proxy_set_header |
proxy_set_header Host $proxy_host; proxy_set_header Connection close; | http、server、location |
需要注意的是,如果想要看到结果,必须在被代理的服务器上来获取添加的头信息。
实例:
server {
listen 80;
server_name mayanan.cn;
location / {
default_type text/plain;
return 200 $http_username;
}
}
server {
listen 80;
server_name flask-test.mayanan.cn;
charset utf-8;
location /server {
proxy_pass http://mayanan.cn/;
proxy_set_header username TOM;
}
}
访问测试:http://flask-test.mayanan.cn/server/
, 返回TOM
客户端访问的是服务器 A,服务器 A 会将请求转发给服务器 B,服务器 B 返回打印 TOM 的页面给服务器 A,服务器 A 最后返回给客户端。
反向代理之proxy_redirect指令
该指令是用来重置头信息中的『 Location 』和『 Refresh 』的值,防止客户端可以看到被代理服务器的地址。
因为客户端看到的返回结果是『 Location 』和『 Refresh 』的值,所以在到达代理服务器的时,将两个值修改掉,防止客户端直接看到被代理服务器的地址。
语法 默认值 位置
proxy_redirect redirect replacement;
proxy_redirect default;
proxy_redirect off; proxy_redirect default; http、server、location
为什么要用该指令
首先说明一下思路:客户端通过代理服务器 A 访问服务器 B 的资源,但是服务器 B 不存在该资源,则会报错。此时我们不希望它直接返回报错页面给客户端,我们希望服务器 B 返回的是它的欢迎页面。那么如何做呢?
首先在服务器 B 进行判断是否存在资源,不存在则返回自己的欢迎页面,即重定向到自己的欢迎页面地址并返回,此时浏览器的地址将会发生改变
代理服务器 A 收到服务器 B 的欢迎页面和地址,但是我们不能直接返回给客户端,因为它会暴露服务器 B 的地址,这是重定向的原因
此时用到 proxy_redirect 指令,重置服务器 B 返回过来的『 Location 』和『 Refresh 』值,将两个值改为代理服务器 A 的某个地址
因为改为了代理服务器 A 的某个地址,所以代理服务器 A 根据这个地址又去获取理服务器 B 的欢迎页面地址,返回给客户端
很绕,简单总结下:客户端通过 A 找 B 不存在的资源,B 不想返回报错页面,于是重定向到自己的欢迎页面地址并返回给 A,A 收到了页面和地址(正常情况不要接收地址,只接收页面),发现不能暴露 B 的地址,于是修改接收的 B 的地址为自己的某一个地址,这个地址会重新发送请求去获取 B 的欢迎页面地址,然后返回给客户端。
这里要明白 B 返回的是重定向后的欢迎页面,重定向后,浏览器地址栏会变成重定向的地址,所以 A 才会以自己的地址转发获取到 B 的地址,所以最后浏览器显示 A 的地址,看到的却是 B 的欢迎页面。
server {
listen 80;
server_name mayanan.cn;
#access_log logs/access.log main;
location / {
root html;
index index.html;
}
location /server {
if (!-f $request_filename) {
return 302 http://mayanan.cn;
}
}
}
server {
listen 80;
server_name flask-test.mayanan.cn;
#access_log logs/access.log main;
charset utf-8;
location /server/abc {
proxy_pass http://mayanan.cn;
proxy_redirect http://mayanan.cn http://flask-test.mayanan.cn;
}
}
修改完之后测试:
root@debian-01:/usr/local/nginx# curl -I http://flask-test.mayanan.cn/server/abc
HTTP/1.1 302 Moved Temporarily
Server: nginx/1.22.0
Date: Sun, 04 Sep 2022 04:01:19 GMT
Content-Type: text/html
Content-Length: 145
Connection: keep-alive
Location: http://flask-test.mayanan.cn
该指令的三组选项
proxy_redirect redirect replacement;
redirect:被代理服务器返回的 Location 值
replacement:要替换 Location 的值
proxy_redirect default;
default:相比较第一组选项,default 仅仅提供了 redirect 和 replacement 的默认值
将本范围 location 块的 uri 变量作为 replacement。
将 proxy_pass 变量作为 redwadairect
server {
listen 8081;
server_name localhost;
location /server {
proxy_pass http://192.168.200.146:8081/;
proxy_redirect default; # redirect 是 proxy_pass 的值:http://192.168.200.146:8081/
# replacement 是 location 后的值:/server
# 等价于:proxy_redirect http://192.168.200.146:8081/ /server
}
}
proxy_redirect off;
关闭 proxy_redirect 的功能
反向代理的实战案例
服务器 1,2,3 存在两种情况
第一种情况: 三台服务器的内容不一样
第二种情况: 三台服务器的内容是一样
第一种情况
如果服务器 1、服务器 2 和服务器 3 的内容不一样,那我们可以根据用户请求来分发到不同的服务器。
服务器有限,只能以三个端口模拟三台服务器,实际上是一个 IP 对应一个服务器。
代理服务器配置文件内容:
server {
listen 80;
server_name mayanan.cn;
location /server1 {
proxy_pass http://flask-test.mayanan.cn/;
}
location /server2 {
proxy_pass http://flask-demo.mayanan.cn/;
}
}
服务器配置文件内容:
server {
listen 80;
server_name flask-test.mayanan.cn;
default_type text/plain;
return 200 'this is server1';
}
server {
listen 80;
server_name flask-demo.mayanan.cn;
default_type text/plain;
return 200 'this is server2';
}