[TOC]
## 什么是proxy(代理)
代理(英语:Proxy),也称网络代理,是一种特殊的网络服务,允许一个网络终端(一般为客户端)通过这个服务与另一个网络终端(一般为服务器)进行非直接的连接。一些网关、路由器等网络设备具备网络代理功能。一般认为代理服务有利于保障网络终端的隐私或安全,防止攻击。
## 代理分类
代理主要分为两大类,正向代理和反向代理。
- 正向代理:
通过一个连接了外网的服务器作为中转站,帮助或代理区域网内的用户访问外网。这个连接了外网的服务器叫做正向代理服务器。
- 反向代理:
通过访问一个内网的**代表**,我们能访问到这整个内网内的数据。这个代表就称作反向代理服务器。
### 正向代理和反向代理的区别
正向代理时,用户在url栏中访问的是直接目标,并不需要关心代理服务器是什么。
反向代理时,用户访问的目标是反向代理服务器,这个反向代理服务器会从内网中拿取数据再传给用户,但用户并不知道**这些数据其实并不是反向代理服务器本身的**。
## 应用
### 设置正向代理
一般我们在公司里需要通过一台连接到外网的服务器作为代理来访问外网。怎么给我们自己设置这个代理服务器呢?
一图顶千言
![](https://box.kancloud.cn/90d0f12dc160296251ac954744abe120_319x285.png)
![](https://box.kancloud.cn/3fd78b4b5e56aabe10a4258cf1ffdca1_741x410.png)
### 代理
我们通常所说的代理是指正向代理,嗯。。能帮助我们做一些不可描述的事情♂。
一般来说一个代理软件会改变我们本地的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添加两个解析
![](https://box.kancloud.cn/c7f595a4416afccb73b7016a19334c4f_502x121.png)
```
www.a.com http://localhost
www.b.com http://localhost
```
可以看到,这两个解析都指向localhost,同一台服务器
为了在同一台服务器上通过访问不同域名访问到应该指向的网站,我们需要讲域名进行一个映射,**映射到服务器上不同的端口号上**。
>[tip] req.headers['host']长这样
![](https://box.kancloud.cn/ec1af685d39fd205d23460a021f2ad71_475x177.png)
这样我们再访问不同站点时,只需从`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' } }
```