Nodejs 第二十六章 反向代理
Nodejs 第二十六章 反向代理
什么是反向代理?
反向代理(Reverse Proxy)是一种服务器,它位于客户端和服务器之间,对外表现为服务器,接受客户端的请求,并将这些请求转发到内部的服务器上处理。当内部服务器处理完成后,反向代理再将响应结果转发给客户端。对于客户端而言,它并不知道实际上请求是被内部的多个服务器处理的。
为什么需要反向代理?
- 负载均衡:反向代理可以将外部的请求分发到内部的多个服务器上,从而均衡负载,避免任何单一服务器的过载,提高整体的处理能力和可靠性。
- 提高安全性:反向代理可以隐藏服务器的真实IP地址和结构,减少直接暴露给外界的风险。它还可以作为应用层的防火墙,提供SSL加密,进行请求过滤等安全措施。
- 缓存静态内容:反向代理可以缓存经常被请求的静态内容(如图片、CSS文件和JavaScript文件),减轻后端服务器的压力,加快内容的加载速度。
- SSL 终端:反向代理可以集中管理SSL证书和加密,处理加密和解密的任务,简化后端服务的配置和维护。
- 压缩和优化内容:反向代理可以在将服务器响应发送到客户端之前进行压缩和优化处理,减少数据传输量,提高响应速度。
反向代理解决的难点
- 服务器安全:反向代理通过隐藏后端服务器的细节,提供了一层额外的安全防护。攻击者无法直接访问真实的服务器,增加了攻击的难度。
- 高可用性和可扩展性:通过负载均衡,反向代理能够在后端服务器之间自动分配流量。这不仅提高了处理能力,也保证了在某台服务器失败时,其他服务器可以接手处理请求,增强了服务的可用性。
- 性能提升:反向代理的缓存机制减少了对后端服务器的直接请求,降低了服务器的负载,并减少了响应时间。
- 维护和监控:反向代理提供了一个集中的点来监控流入的请求和流出的响应,便于进行日志记录、审计和网络监控。
通俗比喻
可以将反向代理比作是一家餐厅的接待人员。客人(客户端)进入餐厅(网站)并向接待人员(反向代理)点菜(发送请求)。接待人员决定将这个订单送到哪个厨师(服务器)那里去准备,可能是基于哪个厨师当前最不忙来决定。厨师准备好食物后,接待人员再将食物提供给客人。这样,客人不需要知道具体哪个厨师为他们服务,而厨师们可以专注于做菜而不被客人直接打扰。
代码实现
-
需要用到一个第三方库:
http-proxy-middleware
- 使用
npm init -y
先生成一个package.json文件
- 通过npm进行安装一下:
npm i http-proxy-middleware
- 创建一个根目录自定义配置文件,也叫反向代理配置文件。命名规则是这样的:xxx.config.js,那我就取名
xiaoyu.config.js
了 - 再创建一个用于处理第三方服务的文件,取名为
test.js
- 最后我们还需要一个index.html的入口文件进行代码测试
- 使用
-
目录结构也是如下:
http-proxy-middleware介绍
http-proxy-middleware
是一个用于 Node.js 的中间件,可以轻松地将代理配置添加到我们的 HTTP 服务器中。这个库通常用于开发环境中,以便将特定的 API 请求转发到其他服务器(例如从开发服务器代理到实际的 API 服务器)。对于处理跨域问题、模拟后端服务、进行负载均衡或简单地将请求从一个端口转发到另一个端口都非常有用。
服务器挂钩入口文件
- 服务端首先需要有内容以及处理好当客户端发送内容过来后,我们要返回什么,我们一开始使用http起的服务是一片空白的,所以我们使用fs模块把入口文件的内容全部读取过来塞进服务里面
const fs = require("node:fs")
const http = require("node:http")
const html = fs.readFileSync('./index.html')
http.createServer((req,res)=>{
// 处理服务器要返回的响应头信息
res.writeHead(200,{
'Content-Type':'text/html'
})
// 把入口文件HTML的内容塞进服务里
res.end(html)
}).listen(3000,()=> {
console.log("3000端口开启成功");
})
- 也是成功将内容塞进我们的3000端口服务里了
代理配置文件
-
通过
http-proxy-middleware
这个第三方库,我们能够进行代理配置。- 这个代理配置文件是可以随便自定义的,但一般我们遵循webpack和vite他们的规范,以module.export导出
module.exports = { // 将对象导出,使得其他文件可以通过require引入这个配置
server: { // 服务器相关的配置
proxy: { // 代理相关的设置
//通常这个选项可以配置多个代理对象的
'/api': { // 指定要代理的路径。这里表明所有以 `/api` 开头的请求都将被代理
target: 'http://localhost:3001', // 转发的目标地址,即实际处理这些请求的服务器地址
changeOrigin: true, // 是否改变源地址,用于控制服务器接收到的请求头中的host字段的值
// 当设置为 true 时,转发请求的 HTTP Host 头会被修改为目标地址
// 这个设置对处理跨域问题非常关键,因为服务器通常会验证这个字段
}
}
}
}
反向代理
-
那写好反向代理的配置文件后,我们就能进行导入我们的服务进行配置了。
- 但这里,如果我们想要等匹配到的时候,再进行反向代理,那要怎么做?
- 匹配到?这是什么意思,其实就是我们路径是有多种多样的,我们可能说只有
/api
接口路径需要反向代理,去针对性的处理
-
那想要做到这一点,我们还是需要拿到我们的路径中,
/
后面的内容。然后和反向代理中的路径进行匹配才能够做到
- 我们通过
内置模块url
进行获取到用户发送请求中的url对应需求的部分 - 然后再拿到反向代理配置文件中
/xxx
的内容部分进行匹配校验判定
const { createProxyMiddleware } = require('http-proxy-middleware')
const config = require('./xiaoyu.config')
//获取到用户传递过来的/后面路径
const { pathname } = url.parse(req.url)
//获取到反向代理中要代理的/路径
const proxyList = Object.keys(config.server.proxy)
//进行两者路径判断,看用户传递过来的路径是否有包含在我们要配置的路径之中
if (proxyList.includes(pathname)) {
const proxy = createProxyMiddleware(config.server.proxy[pathname]) //代理
proxy(req, res)
return
}
-
到这一步还没有结束,还记得我们一开始创建好的
test.js文件
没?- 我们要将
3000端口
反向代理到3001端口
,但我们3001端口
暂时还没起服务,所以一旦代理过去,就会落空,然后报错。为此我们要在这个test.js文件中,起一个最简单的空白服务,来验证我们是否能够把内容代理过去
- 我们要将
//test.js文件
const http = require('node:http')
const url = require('node:url')
const http = require('node:http')
http.createServer((req,res) => {
const { pathname } = url.parse(req.url)
if (pathname === '/api') {
res.end('success proxy')//告诉用户,我们成功开启反向代理了
}
}).listen(3001, () => {
console.log("3001端口成功开启");
})
- 最后,我们还需要发起请求,这个我们就直接在index.html中使用fetch发起请求,充当客户端。而index.js开启的3000端口服务充当服务端,test.js开启的3001端口空白服务充当中间的反向代理层
<body>
<script>
fetch('/api').then(res => res.text()).then(res => {
console.log(res);
})
</script>
<h1>Hello World 我是小余</h1>
</body>
-
也是成功的将内容代理到了3001端口,我们来梳理一下目前的流程:
- 首先,我们起了两个服务,一个入口index.html文件。其中入口文件起到客户端发送请求的作用,而两个服务分别充当了服务端(3000端口)和反向代理层(3001端口)
- 我们将入口文件的内容传递到了3000端口中,而这里的内容就有向
/api
路径发送请求。 - 而我们在3000端口的
index.js文件
有进行提前的处理了,我们将xiaoyu.config.js
这个配置文件内的/xxx
路径拿出来看是否包含客户端发送过来的请求,有则进行反向代理(通过第三方库和反向代理配置文件看代理到哪个端口,这里是代理到了3001端口),没有就正常请求 - 最后,我们从浏览器打开了3000端口,内容是正常的显示我们读取入口文件的内容,然后打开控制台,看
/api
返回的相应内容来自哪里。原来是来自test.js,也就是说,我们对着3000端口发送的请求成功的被3001端口给接收了,并且正确的返回了内容。反向代理完美成功!
总结
- 客户端到服务端的请求:通过在
index.html
中的fetch('/api')
请求,客户端(浏览器)向 Node.js 服务器(在 3000 端口上运行的index.js
)发送请求。 - 反向代理处理:在
index.js
中,根据xiaoyu.config.js
的配置,检测到请求路径为/api
,并根据配置将请求代理到另一个 Node.js 服务(在 3001 端口上运行的test.js
)。 - 验证反向代理的成功:
test.js
接收到经过 3000 端口转发的/api
请求,并返回"success proxy"
。浏览器最终接收到来自 3001 端口服务的响应,验证了反向代理的设置是成功的。
转载自:https://juejin.cn/post/7361261846089564210