什麼是proxy(代理)
代理(英語:Proxy),也稱網路代理,是一種特殊的網路服務,允許一個網路終端(一般為客戶端)通過這個服務與另一個網路終端(一般為伺服器)進行非直接的連線。一些閘道器、路由器等網路裝置具備網路代理功能。一般認為代理服務有利於保障網路終端的隱私或安全,防止攻擊。
代理分類
代理主要分為兩大類,正向代理和反向代理。
-
正向代理: 通過一個連線了外網的伺服器作為中轉站,幫助或代理區域網內的使用者訪問外網。這個連線了外網的伺服器叫做正向代理伺服器。
-
反向代理: 通過訪問一個內網的代表,我們能訪問到這整個內網內的資料。這個代表就稱作反向代理伺服器。
正向代理和反向代理的區別
正向代理時,使用者在url欄中訪問的是直接目標,並不需要關心代理伺服器是什麼。 反向代理時,使用者訪問的目標是反向代理伺服器,這個反向代理伺服器會從內網中拿取資料再傳給使用者,但使用者並不知道這些資料其實並不是反向代理伺服器本身的。
應用
設定正向代理
一般我們在公司裡需要通過一臺連線到外網的伺服器作為代理來訪問外網。怎麼給我們自己設定這個代理伺服器呢? 一圖頂千言
代理
我們通常所說的代理是指正向代理,嗯。。能幫助我們做一些不可描述的事情♂。
一般來說一個代理軟體會改變我們本地的host指向,當我們在url中輸入一個網址(域名)時,先會解析到代理伺服器上(這個伺服器要和我們的目標網址連的上),然後才是代理伺服器幫助我們向使用者的目標地址發起請求,當得到目標地址響應後代理伺服器再轉將響應資訊傳輸給客戶端。
let http = require('http');
let proxy = require('http-proxy');
let proxyServer = proxy.createProxyServer();
let {inspect} = require('util');
// 代理伺服器
let server = http.createServer(function(req,res){
proxyServer.web(req,res,{
target:'http://localhost:9999'
})
proxy.on('error', function (err) {
console.log(inspect(err));
res.end('somthing wrong');
});
}).listen(8888)
//--- --- ---
// 目標地址伺服器
let http = require('http');
let server = http.createServer(function(req,res){
res.write('9999,');
res.end('9999');
}).listen(9999);
複製程式碼
proxyServer.web()方法實現思路
function web(req,res,options){
let {host,port,pathname} = url.parse(req.url);
let opts = {
host
,port
,method:req.method
,path:pathname
,header:req.headers
};
opts.host = options.target;
console.log('-----------')
http.request(opts,function(response){
console.log(response);
response.pipe(res);
});
}
複製程式碼
虛擬機器
伺服器與虛擬主機
首先我們來看看伺服器和虛擬主機的區別 以阿里雲等為例, 彈性計算雲伺服器 ECS:一個完整的伺服器 虛擬主機:你得到的只是此伺服器上的一個目錄
這裡有個問題,一臺ECS上能建立多個虛擬主機(網站),但我們訪問的時候都是通過同一個埠號訪問的,眾所周知,一個埠只能有一個程式,這麼多個站點怎麼就會不報錯呢?
這就是通過反向代理來實現了。
虛擬機器與反向代理
下面我們通過一個簡單的示例來演示反向代理怎麼來實現虛擬機器的。
為了演示,首先我們在etc下的hosts新增兩個解析
www.a.com http://localhost
www.b.com http://localhost
複製程式碼
可以看到,這兩個解析都指向localhost,同一臺伺服器 為了在同一臺伺服器上通過訪問不同域名訪問到應該指向的網站,我們需要將域名進行一個對映,對映到伺服器上不同的埠號上。
[tip] req.headers['host']長這樣
這樣我們再訪問不同站點時,只需從req
中拿到的host
,再根據host查詢到對映到的那個埠就可以找到執行在該埠上的站點。
示例原始碼
let http = require('http');
let proxy = require('http-proxy');
let proxyServer = proxy.createServer();
let config = {
"www.a.com":"http://localhost:8080"
,"www.b.com":"http://localhost:9000"
};
let server = http.createServer(function(req,res){
let host = req.headers['host'];
console.log(host);
let target = config[host];
console.log(target);
if(target){
proxyServer.web(req,res,{
target
})
}else{
res.end(host);
}
}).listen(80);
//--- --- ---
// a.com
let http = require('http');
let server = http.createServer(function(req,res){
res.end('8080');
}).listen(8080);
//b.com
let http = require('http');
let server = http.createServer(function(req,res){
res.end('9000');
}).listen(9000);
複製程式碼
請求報文中的user-agent
此代理非彼代理,這裡是指客戶端(瀏覽器和作業系統計算機硬體)的一些資訊。我們可通過req.headers['user-agent']
拿到這些資訊,並根據這些資訊對我們的應用進行一定的定製優化。
let http = require('http');
let userAgentParser = require('user-agent-parser');
let server = http.createServer(function(req,res){
let userAgent = req.headers['user-agent'];
console.log(userAgent);
let userAgentObj = userAgentParser(userAgent);
console.log(userAgentObj);
}).listen(8080);
<<< userAgentObj
{ browser: { name: 'Chrome', version: '64.0.3282.186', major: '64' },
engine: { name: 'WebKit', version: '537.36' },
os: { name: 'Windows', version: '7' },
device: { model: undefined, vendor: undefined, type: undefined },
cpu: { architecture: 'amd64' } }
複製程式碼