nodejs代替goagent
转载http://www.cnblogs.com/hackwaly/archive/2012/06/23/2559474.html
以前一直在用goagent fq,不过受限于gae,goagent有两个比较明显的缺点:一是不支持socks,二是访问https网站需要安装证书。
趁着端午节的空闲时间,琢磨着找一个国外的免费的nodejs的AppEngine,然后写一个代理部署到上面,也就可以 fq 了
我选择的是http://nodejitsu.com,现在还处于private beta,开放注册,可以免费试用。除了它我目前还没有找到免费的可用的并且支持net模块的appEngine了。
要注意两点:
1,申请稍微麻烦一点,需要npm安装一个jitsu的客户端进行验证,这也是防止不会用的人瞎申请浪费。
2,目前nodejitsu每个app只允许绑定一个80端口,这个端口不支持tcp(它的宣传里说支持任意多个端口,但坑我了一个下午才在它的github里找到说明,是以后会支持),原因是nodejitsu使用http协议里的"Host" header来实现公网到app之间的路由。
由于nodejitsu不支持tcp端口的监听,所以得走一个http的tunnel才行,这就要求我们实现一个服务器端和一个客户端,由客户端提供socks代理端口,而代理请求则通过httptunnel交给服务器端去处理。
socks5服务器的实现代码我就不贴了,大家可以参考https://github.com/gvangool/node-socks
里面建立连接的时候是直接建立连接的,所以在本地跑的话,没有 fq效果,只能作为代理使用,我们需要把建立连接的部分替换成建立http tunnel的连接。
下面是代码:
客户端建立httptunnel连接部分
var http = require('http');var net = require('net');var querystring = require('querystring');function fromBase64(str){ return new Buffer(str, 'base64').toString();}http.createServer(function (req, res){ var url = req.url; // 这里解码path为host和port var params = JSON.parse(fromBase64(querystring.unescape(url.slice(1)))); var host = params.host; var port = params.port; console.log('CONNECT: ' + host + ':' + port); var buff = []; function addChunk(chunk){ buff.push(chunk); } // 忽略第一个用来强制http发包的'\n' req.once('data', function (chunk){ if (chunk.toString() === '\n') { req.on('data', addChunk); } }); var socket = net.connect(port, host, function (){ req.removeListener('data', addChunk); res.writeHead(200); // 貌似nodejs为了优化, writeHead并不会立即响应给客户端. // 所以这里需要额外发一个没用的字符. res.write('\n'); for (var i=0; i<buff.length; i++) { socket.write(buff[i]); } req.pipe(socket); socket.pipe(res); console.log('CONNECTED: ' + host + ':' + port); });}).listen(80);