解决一个历史遗留问题:
博客上线后第一篇关于Nodejs的博客就是——Nodejs绑定域名与反向代理;是关于Nodejs的代理设置,到现在为止线上几个二级小站也还是在使用那个http-proxy模块,却怎么也没想到,这些小站的一个共同的遗留问题也源自这个代理模块;问题在于:用已知的各种方式获取到的访问者的ip永远为127.0.0.1;拜托不要提os模块了,os可以获取本站ipv4的值,除此值以外,根本没有第二个ipv4的字段好嘛!
比如以博客为主站,cdn为二级站点,代理模块是这样的,像下面这样,问题就在其中:
var http = require('http'),
httpProxy = require('http-proxy'),
proxy = httpProxy.createProxyServer({});
proxy.on('error', function (err, req, res) {
res.writeHead(500, {
'Content-Type': 'text/plain'
});
res.end('Something went wrong.');
});
var server = require('http').createServer(function(req, res) {
var host = req.headers.host;
switch (host){
case 'cdn.famanoder.cn':
proxy.web(req, res, { target: 'http://localhost:4000' });
break;
case 'www.famanoder.cn':
proxy.web(req, res, { target: 'http://localhost:3000' });
break;
default:
proxy.web(req, res, { target: 'http://localhost:3000' });
}
});
server.listen(80);
这里是新建了一个server来监听80端口,然后根据所有请求的host,将请求代理到目标站点;如果访问首页http://famanoder.com那么将会被代理到服务器上的3000端口的站点,也就是说,我只是自认为我访问首页就是直接访问3000端口,而其实是通过一个额外的server代理过去的,所以我在所有站点里获取到的ip永远为127.0.0.1,因为代理过来后域从famanoder.com变为了localhost;
从上面的代理设置,可以看出两个问题:
1、这里新建的一个server是多余的;
2、不能将所有站点包括在代理设置内;
2.5、抱歉,请原谅我这个不完美的小孩;
既然这个server是多余的,那么先将其去掉;
既然不能将所有站点包括在代理设置内,那么就留下博客做主站监听80端口;
那么就应该在主站里分发二级站点了,事实也证明主站里监听80端口后,通过express的req.ip就能获取到访问者的ip了,同上,二级站点现在是被代理转发的,所以依然拿不到真实的访问者的ip;
既然主站现在可以拿到ip,二级站点又是由主站分发出去的,那么在转发之前通过设置转发请求的header,二级站点从header上不就可以拿到从主站传过来的ip了吗!
在express里,现在可以将这个代理设置作为一个中间件来对待,将访问者的ip由请求header带过去:
app.use(function(req,res,next){
console.log(req.ip);
var proxy = httpProxy.createProxyServer({
headers:{
'x-forward-ip':req.ip.match(/([\w\.]+)/g)[1]
}
});
proxy.on('error', function (err, req, res) {
res.writeHead(500, {
'Content-Type': 'text/plain'
});
res.end('Something went wrong.');
});
var host = req.headers.host;
switch (host){
case 'cdn.famanoder.cn':
proxy.web(req, res, { target: 'http://localhost:4000' });
break;
default:
next();//主站不再被转发,next()是必需的!!!
}
});
如上:添加了代理设置的headers项,二级站点将由req.header('x-forward-ip')来获取访问者的ip;
用http-proxy解决跨域问题:
如果a.com要请求b.com的接口,涉及到跨域问题,除了jsonp之外,通过http-proxy设置代理,可以直接请求a.com,然后由proxy将a.com转发到b.com实现跨域;
case 'a.com':
proxy.web(req, res, { target: 'http://b.com' });
break;
因为跨域问题只存在于前端,后端根本不涉及到跨域问题;现在感觉http-proxy是通过http.request来实现的转发,可能就是切换host;
原文来自:花满楼(http://famanoder.com/bokes)
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。