這篇文章主要介紹“如何手動實現nodejs代理服務器”,在日常操作中,相信很多人在如何手動實現nodejs代理服務器問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”如何手動實現nodejs代理服務器”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
目前創(chuàng)新互聯建站已為上千的企業(yè)提供了網站建設、域名、網站空間、網站托管運營、企業(yè)網站設計、襄城網站維護等服務,公司將堅持客戶導向、應用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶和合作伙伴齊心協(xié)力一起成長,共同發(fā)展。
最近看到這樣一個題目,根據反向代理服務器的原理用nodejs實現一個代理服務器,要求:
1、不允許使用第三方包。
2、能夠代理get請求。
3、能夠代理post請求。
起初看到這個題目的時候,內心以為這沒啥呀 ,因為前面發(fā)表過一篇文章:用nodejs搭建代理服務器,但是再仔細閱讀要求后發(fā)現,有點不同,先前的文章使用了express和http-proxy-middleware這兩個第三方包。但是這個題目要求不能使用第三方模塊。
所以本篇文章便使用nodejs原生模塊實現一個代理服務器,首先我們了解下代理服務器的原理,通過如下這張圖來了解一下代理服務器:
從圖中我們可以看到,代理服務器的作用是中轉作用,接收客戶端請求,將請求發(fā)送到被代理的服務器。
我們從代理服務器的原理推斷一下代理服務器的實現方式:
1、首先應該搭建一個http服務器,這里我們使用nodejs的http模塊的createServer方法。
2、接收客戶端發(fā)送的請求,那什么是客戶端發(fā)送的請求呢?通俗一點就是請求報文,請求報文在拆解一下,包括請求行,請求頭,請求體。
3、將請求報文發(fā)送到目標服務器,這里需要使用http模塊的request方法。
思路理清了說干就干,代碼如下,第一步搭建http服務器,代碼如下:
const http = require("http");
const server = http.createServer();
server.on('request',(req,res)=>{
res.end("hello world")
})
server.listen(3000,()=>{
console.log("running");
})
很簡單的代碼,無需做過多解釋,接著實現第二步驟,接收客戶端發(fā)送到代理服務器的請求報文,并作測試將其打印出來:
const http = require("http");const server = http.createServer();server.on('request',(req,res)=>{ // 通過req的data事件和end事件接收客戶端發(fā)送的數據 // 并用Buffer.concat處理一下 let postbody = []; req.on("data", chunk => { postbody.push(chunk); }) req.on('end', () => { let postbodyBuffer = Buffer.concat(postbody); res.end(postbodyBuffer) })})server.listen(3000,()=>{ console.log("running");})
運行上面代碼,可以接收到客戶端發(fā)送的數據,并可以返回給客戶端,大家可以測試一下,這里主要數據在客戶端到服務器端進行傳輸時在nodejs中需要用到buffer來處理一下。
處理過程就是將所有接收的數據片段chunk塞到一個數組中,然后將其合并到一起還原出源數據。合并方法需要用到Buffer.concat,這里不能使用加號,加號會隱式的將buffer轉化為字符串,這種轉化不安全。
之后是第三步驟,使用http模塊的request方法,將請求報文轉發(fā)到目標服務器,在這一步我們要構造請求報文,上一步我們已經得到了客戶端上傳的數據,還缺少請求頭,所以我們要根據客戶端發(fā)送的請求構造我們的請求頭,然后發(fā)送,代碼如下:
const http = require("http");const server = http.createServer();server.on('request',(req,res)=>{ // 使用es6的擴展運算符過濾請求頭,提出host connection var { connection, host, ...originHeaders } = req.headers; // 構造請求報文 var options = { "method": req.method, "hostname": "127.0.0.1", "port": "80", "path": req.url, "headers": { originHeaders } } // 通過req的data事件和end事件接收客戶端發(fā)送的數據 // 并用Buffer.concat處理一下 let postbody = []; req.on("data", chunk => { postbody.push(chunk); }) req.on('end', () => { let postbodyBuffer = Buffer.concat(postbody); // 定義變量接收目標服務器返回的數據 let responsebody=[] // 發(fā)送請求頭 var request = http.request(options, (response) => { response.on('data', (chunk) => { responsebody.push(chunk) }) response.on("end", () => { // 處理目標服務器數據,并將其返回給客戶端 responsebodyBuffer = Buffer.concat(responsebody) res.end(responsebodyBuffer); }) }) // 將接收到的客戶端請求數據發(fā)送到目標服務器; request.write(postbodyBuffer) request.end(); })})server.listen(3000,()=>{ console.log("running");})
以上便是用http模塊實現的原生代理服務器了,這里我們使用了es6的擴展運算符、解構來過濾了請求頭,并使用了http模塊的request方法。
http模塊的request方法使用的時候需要傳遞兩個參數,并且這個方法會返回一個request對象。
這個方法的第一個參數為請求頭信息或者更嚴格的來說是請求行和請求頭信息,第二個參數為回調函數,這個函數來獲取目標服務器返回的內容,在獲取內容的時候又用到了data事件、end事件和buffer的處理,但是到目前為止,我們還沒有設置請求體,一個完整的請求報文應該包含請求行、請求頭和請求體,那么請求體通過什么方式來發(fā)送呢,通過36行的request的對象調用write方法傳遞請求體。
然后調用在調用37行的end方法,將請求發(fā)送出去。
但是看著這么多的回調嵌套,實在是不能忍,我們簡單的用promise優(yōu)化一下,代碼如下:
const http = require("http");
const server = http.createServer();
server.on("request", (req, res) => {
var { connection, host, ...originHeaders } = req.headers;
var options = {
"method": req.method,
// 隨表找了一個網站做測試,被代理網站修改這里
"hostname": "www.nanjingmb.com",
"port": "80",
"path": req.url,
"headers": { originHeaders }
}
//接收客戶端發(fā)送的數據
var p = new Promise((resolve,reject)=>{
let postbody = [];
req.on("data", chunk => {
postbody.push(chunk);
})
req.on('end', () => {
let postbodyBuffer = Buffer.concat(postbody);
resolve(postbodyBuffer)
})
});
//將數據轉發(fā),并接收目標服務器返回的數據,然后轉發(fā)給客戶端
p.then((postbodyBuffer)=>{
let responsebody=[]
var request = http.request(options, (response) => {
response.on('data', (chunk) => {
responsebody.push(chunk)
})
response.on("end", () => {
responsebodyBuffer = Buffer.concat(responsebody)
res.end(responsebodyBuffer);
})
})
request.write(postbodyBuffer)
request.end();
})
});
server.listen(3000, () => {
console.log("runnng");
})
仔細閱讀源碼,第一個promise實例里面主要處理接收客戶端發(fā)送的數據,然后then方法中,我們將上一步得到的數據轉發(fā),并接收目標服務器返回的數據,然后將其轉發(fā)給客戶端。
到此,關于“如何手動實現nodejs代理服務器”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續(xù)學習更多相關知識,請繼續(xù)關注創(chuàng)新互聯網站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>
本文題目:如何手動實現nodejs代理服務器
鏈接分享:http://weahome.cn/article/gchjgg.html