什么是proxy(代理)
代理(英語(yǔ):Proxy)隅居,也稱網(wǎng)絡(luò)代理曹铃,是一種特殊的網(wǎng)絡(luò)服務(wù)署浩,允許一個(gè)網(wǎng)絡(luò)終端(一般為客戶端)通過(guò)這個(gè)服務(wù)與另一個(gè)網(wǎng)絡(luò)終端(一般為服務(wù)器)進(jìn)行非直接的連接扮休。一些網(wǎng)關(guān)蔗怠、路由器等網(wǎng)絡(luò)設(shè)備具備網(wǎng)絡(luò)代理功能。一般認(rèn)為代理服務(wù)有利于保障網(wǎng)絡(luò)終端的隱私或安全它匕,防止攻擊展融。
代理分類
代理主要分為兩大類,正向代理和反向代理豫柬。
正向代理:
通過(guò)一個(gè)連接了外網(wǎng)的服務(wù)器作為中轉(zhuǎn)站告希,幫助或代理區(qū)域網(wǎng)內(nèi)的用戶訪問(wèn)外網(wǎng)。這個(gè)連接了外網(wǎng)的服務(wù)器叫做正向代理服務(wù)器烧给。反向代理:
通過(guò)訪問(wèn)一個(gè)內(nèi)網(wǎng)的代表燕偶,我們能訪問(wèn)到這整個(gè)內(nèi)網(wǎng)內(nèi)的數(shù)據(jù)。這個(gè)代表就稱作反向代理服務(wù)器础嫡。
正向代理和反向代理的區(qū)別
正向代理時(shí)指么,用戶在url欄中訪問(wèn)的是直接目標(biāo),并不需要關(guān)心代理服務(wù)器是什么。
反向代理時(shí)伯诬,用戶訪問(wèn)的目標(biāo)是反向代理服務(wù)器晚唇,這個(gè)反向代理服務(wù)器會(huì)從內(nèi)網(wǎng)中拿取數(shù)據(jù)再傳給用戶,但用戶并不知道這些數(shù)據(jù)其實(shí)并不是反向代理服務(wù)器本身的姑廉。
應(yīng)用
設(shè)置正向代理
一般我們?cè)诠纠镄枰ㄟ^(guò)一臺(tái)連接到外網(wǎng)的服務(wù)器作為代理來(lái)訪問(wèn)外網(wǎng)。怎么給我們自己設(shè)置這個(gè)代理服務(wù)器呢翁涤?
一圖頂千言
代理
我們通常所說(shuō)的代理是指正向代理桥言,嗯。葵礼。能幫助我們做一些不可描述的事情♂号阿。
一般來(lái)說(shuō)一個(gè)代理軟件會(huì)改變我們本地的host指向,當(dāng)我們?cè)趗rl中輸入一個(gè)網(wǎng)址(域名)時(shí)鸳粉,先會(huì)解析到代理服務(wù)器上(這個(gè)服務(wù)器要和我們的目標(biāo)網(wǎng)址連的上)扔涧,然后才是代理服務(wù)器幫助我們向用戶的目標(biāo)地址發(fā)起請(qǐng)求,當(dāng)?shù)玫侥繕?biāo)地址響應(yīng)后代理服務(wù)器再轉(zhuǎn)將響應(yīng)信息傳輸給客戶端届谈。
let http = require('http');
let proxy = require('http-proxy');
let proxyServer = proxy.createProxyServer();
let {inspect} = require('util');
// 代理服務(wù)器
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)
//--- --- ---
// 目標(biāo)地址服務(wù)器
let http = require('http');
let server = http.createServer(function(req,res){
res.write('9999,');
res.end('9999');
}).listen(9999);
proxyServer.web()方法實(shí)現(xiàn)思路
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);
});
}
虛擬機(jī)
服務(wù)器與虛擬主機(jī)
首先我們來(lái)看看服務(wù)器和虛擬主機(jī)的區(qū)別
以阿里云等為例枯夜,
彈性計(jì)算云服務(wù)器 ECS:一個(gè)完整的服務(wù)器
虛擬主機(jī):你得到的只是此服務(wù)器上的一個(gè)目錄
這里有個(gè)問(wèn)題,一臺(tái)ECS上能創(chuàng)建多個(gè)虛擬主機(jī)(網(wǎng)站)艰山,但我們?cè)L問(wèn)的時(shí)候都是通過(guò)同一個(gè)端口號(hào)訪問(wèn)的湖雹,眾所周知,一個(gè)端口只能有一個(gè)程序曙搬,這么多個(gè)站點(diǎn)怎么就會(huì)不報(bào)錯(cuò)呢摔吏?
這就是通過(guò)反向代理來(lái)實(shí)現(xiàn)了。
虛擬機(jī)與反向代理
下面我們通過(guò)一個(gè)簡(jiǎn)單的示例來(lái)演示反向代理怎么來(lái)實(shí)現(xiàn)虛擬機(jī)的纵装。
為了演示征讲,首先我們?cè)趀tc下的hosts添加兩個(gè)解析
www.a.com http://localhost
www.b.com http://localhost
可以看到,這兩個(gè)解析都指向localhost橡娄,同一臺(tái)服務(wù)器
為了在同一臺(tái)服務(wù)器上通過(guò)訪問(wèn)不同域名訪問(wèn)到應(yīng)該指向的網(wǎng)站诗箍,我們需要講域名進(jìn)行一個(gè)映射,映射到服務(wù)器上不同的端口號(hào)上挽唉。
[tip] req.headers['host']長(zhǎng)這樣
image
這樣我們?cè)僭L問(wèn)不同站點(diǎn)時(shí)扳还,只需從req
中拿到的host
,再根據(jù)host查找到映射到的那個(gè)端口就可以找到運(yùn)行在該端口上的站點(diǎn)橱夭。
示例源碼
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);
請(qǐng)求報(bào)文中的user-agent
此代理非彼代理氨距,這里是指客戶端(瀏覽器和操作系統(tǒng)計(jì)算機(jī)硬件)的一些信息。我們可通過(guò)req.headers['user-agent']
拿到這些信息棘劣,并根據(jù)這些信息對(duì)我們的應(yīng)用進(jìn)行一定的定制優(yōu)化俏让。
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' } }