最近研究了一下怎么用Nodejs来写一个http代理服务器,起因就是因为公司网络管理太过严格,服务器访问其他服务器总是要申请权限。
我们NGINX服务器上设置了一些反向代理需要将请求转发到其他的后端服务器,然而我们刚新建的服务器没有权限,但是最近公司IT都放假了,申请权限也来不及了。
跟部门后台大佬讨论了一下,大佬一语点醒了我,他说可以用公司上网代理代理过去。服务器申请了访问上网代理服务器的权限,而且代理服务器也属于公司内网。
下面开始着手写一个http代理服务。
首先先了解一下HTTP代理的原理:
代理服务器是介于浏览器和Web服务器之间的一台服务器,有了它之后,浏览器不是直接到Web服务器去取回网页而是向代理服务器发出请求,Request信号会先送到代理服务器,由代理服务器来取回浏览器所需要的信息并传送给你的浏览器。
现在知道代理服务器就是浏览器将请求发送到代理服务器,代理服务器再去请求对应的地址。下一个问题就是浏览器是通过什么样的方式去告诉代理服务器目标地址是什么呢?这在《HTTP权威指南》第六章中6.5中有介绍:
客户端向服务器而不是代理发送请求时,HTTP请求报文中的URI会有所不同。客户端向Web服务器发送请求时,请求行中只包含部分URI(没有方案、主机或端口),但当客户端向代理发送请求时,请求行中则包含完整的URI。
现在基本清楚了,开始着手撸代码了。
一、创建一个HTTP服务器
根据上面的了解,代理服务器既是一个HTTP服务器也是一个HTTP客户端,所以我们先创建一个HTTP服务器:
// index.js
const http = require('http')
const PORT = 3128
const server = http.createServer()
server.on('request', (req, res) => {
console.log(req.url)
let reqBody = ''
req.on('data', chunk => {
reqBody += chunk
})
req.on('end', () => {
res.end('Request is receive.')
})
})
server.on('error', err => {
console.error(err)
})
server.listen(PORT, () => {
console.log(`Server is running at port ${PORT}`)
})
运行起来:
打开浏览器访问http://localhost:3128
:
是我们预期的结果,OK!
上面这个服务器我们是用来做代理服务器的,我们一样画葫芦,再写一个http服务器,用于提供正常Web服务的,新建一个webHttpServer.js
文件,并在index.js中导入,我就不再贴代码了,Web服务器运行在80端口。
在hosts文件中创建一条解析记录:127.0.0.1 www.monster.com
设置代理到localhost:3128
:
这就相当于将到www.monster.com
的请求发送到了代理服务器。
二、读取请求头信息,并发送到目标服务器
根据上面对代理服务器原理的介绍,我们需要读取http请求头中的URI(即req.url
)和方法:
const http = require('http')
require('./webHttpServer');
const PORT = 3128
const server = http.createServer()
// 接收到客户端的请求
server.on('request', (req, res) => {
console.log(req.method, req.url)
// 接收客户端上传的数据
let reqBody = ''
req.on('data', chunk => {
reqBody += chunk
})
// 请求完成
req.on('end', () => {
// res.end('Request is receive.')
// 读取真实的URL和请求方法
const { url, method } = req
// 向目标服务器发送请求
const proxyReq = http.request({
method,
path: url,
}, targetRes => {
// 接收目标服务器的响应数据
let targetData = ''
targetRes.on('data', chunk => {
targetData += chunk
console.log('data from target server: ', chunk.toString())
})
// 响应完毕,开始向客户端发送响应头和响应数据
targetRes.on('end', () => {
res.writeHead(
targetRes.statusCode,
targetRes.statusMessage,
targetRes.headers
)
res.end(targetData)
})
// 监听错误
targetRes.on('error', err => {
console.error(err)
res.writeHead(
500,
'Proxy Error'
)
res.end()
})
})
// 向目标服务器发送数据
proxyReq.write(reqBody)
// 结束向目标服务器的请求
proxyReq.end()
console.log('rquest end.')
})
})
server.on('error', err => {
console.error(err)
})
server.listen(PORT, () => {
console.log(`Proxy Server is running at port ${PORT}`)
})
效果:
代理服务器开发完成,大功告成!
共同学习,写下你的评论
评论加载中...
作者其他优质文章