时间:2024-3-29 作者:fanlepian 分类: 无
前段时间我自己尝试做一个使用nodejs的网站demo,使用了自己家里的废旧笔记本作为服务端,因为涉及到家宽不给开80端口的原因,我选择使用虚拟主机然后反向代理我的网站demo。可是在我反向代理的时候遇到一个问题,反向代理请求用的IP是虚拟主机自己的IP,并不是访问者的IP。
这样就很不方便我们后期的运维,毕竟使用反向代理的目的一是为了让他能够通过80端口访问出去,二是作为一个防护作用,不让自己的家宽暴露出去,所以大多数用户都是要通过虚拟主机来访问我的代码的。如果没有吗好的解决办法就后面就很难运维了。
nginx的反向代理在配置文件里是这个样子的,使用了proxy_pass来转到我的家宽上面。这样子做就是完全使用虚拟主机进行访问了,可是这样的配置文件还并不是完整的
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 REMOTE-HOST $remote_addr;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;
里面的$host
代表着请求时发送给服务端的名称,这里面填入的是nginx中的内置变量,变量的含义就是proxy_pass
中所代理网站的名称,一般不用修改proxy_set_header X-Real-IP $remote_addr;
这条指令将客户端的原始IP地址设置为X-Real-IP
头部发送给后端服务器。$remote_addr
是Nginx内置变量,它代表了客户端的IP地址。proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
这条指令将X-Forwarded-For
头部设置为Nginx代理添加的值。$proxy_add_x_forwarded_for
是Nginx内置变量,它代表了使用这个代理的客户端的IP地址,这个是必不可少的proxy_set_header REMOTE-HOST $remote_addr;
这条指令将客户端的IP地址设置为REMOTE-HOST
头部发送给后端服务器。这里使用的是$remote_addr
变量,其作用和上面解释的一样。不过,通常X-Forwarded-For
头部更常用,所以一般没什么用,但是有一些后端服务端也是需要这样的请求头参数的,最好还是加上proxy_set_header Upgrade $http_upgrade;
这条指令将客户端的Upgrade
头部的值设置为后端服务器请求的头部值。$http_upgrade是Nginx
内置变量,它代表了客户端在请求中发送的Upgrade
头部的值,通常用于HTTP到WebSocket的协议升级,为了确保ws协议正常工作,最好还是加上他proxy_set_header Connection $connection_upgrade;
这条指令将客户端的Connection
头部的值设置为后端服务器请求的头部值。$connection_upgrade
是Nginx内置变量,它代表了客户端在请求中发送的Connection
头部的值,通常与WebSocket协议升级一起使用。只是在反向代理配置中添加了上面的几行代码,也是没用的,重要的也是服务端的,我先用nodejs写出一个打印请求头的示例,来分析一下整个请求头包含的内容
const http = require('http');
const server = http.createServer((req, res) => {
// 打印请求头
console.log(JSON.stringify(req.headers));
// 设置响应状态码和内容类型
res.writeHead(200, {'Content-Type': 'text/plain'});
// 发送响应内容
res.end('DONE!');
});
// 监听3000端口
server.listen(3000, () => {
console.log('服务端开启');
});
当我使用本地连接服务端的时候,他的请求头是这样的
{"host":"127.0.0.1:3000","connection":"keep-alive","sec-ch-ua":"\"Chromium\";v=\"122\", \"Not(A:Brand\";v=\"24\", \"Microsoft Edge\";v=\"122\"","sec-ch-ua-mobile":"?0","user-agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 Edg/122.0.0.0","sec-ch-ua-platform":"\"Windows\"","accept":"image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8","sec-fetch-site":"same-origin","sec-fetch-mode":"no-cors","sec-fetch-dest":"image","referer":"http://127.0.0.1:3000/","accept-encoding":"gzip, deflate, br","accept-language":"zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6"}
这是使用反向代理之后的请求头
{"host":"fanmail.x3322.net","x-real-ip":"112.234.137.8","x-forwarded-for":"112.234.137.8","remote-host":"112.234.137.8","connection":"close","user-agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 Edg/122.0.0.0","accept":"image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8","referer":"http://fanmail.x3322.net/","accept-encoding":"gzip, deflate","accept-language":"zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6"}
从中对比我们可以看出在下面的请求头中多出了三个参数,x-forwarded-for
remote-host
x-real-ip
,这三个看请求头中的数据都是一样的112.234.137.8这个IP,但是,这三个表达的意思是不一样的,通过上面的解释也可以看出来,因为我这里没有多的虚拟主机来做演示了,所以这三个IP都是一样的,如果我在另外一台虚拟主机上反向代理这台虚拟主机,那么请求头返回的地址就不一样了,x-forwarded-for
返回的是用户的真实IP,remote-host
x-real-ip
返回的是另外一台虚拟主机的IP。所以我们在写服务端代码的时候要用x-forwarded-for
的请求参数中的IP地址。为了使我们的代码没有问题,我们还要做一些判定,如果请求头中没有x-forwarded-for
参数,就没法获取x-forwarded-for
参数,就只能获取他请求时带的IP了。
const http = require('http');
const server = http.createServer((req, res) => {
// 检查请求头中是否存在 X-Forwarded-For 字段
const xForwardedFor = req.headers['x-forwarded-for'];
// 如果存在,打印出来,不存在打印请求IP
if (xForwardedFor) {
console.log('X-Forwarded-For:', xForwardedFor);
} else {
console.log(req.connection.remoteAddress);
}
// 发送响应
res.end('DONE!');
});
server.listen(3000, () => {
console.log('服务器开启');
});