如何提高NodeJS程序的稳定性
2011-05-16

   当我们写了个NodeJS程序的时候,一般用node yourjsfile.js命令启动该程序。但是如果程序中有东西出错,这个进程就会退出。我们写程序不可能保证万无一失,肯定有些没有处理的错误,这就让很多人觉得NodeJS不稳定,容易产生很多故障。 下面我就讲讲几种方法增加你的NodeJS程序的稳定性。

   1.使用 try{...} catch(error){...} 来执行容易出错的代码段。比如解析一个外来的json字符串等。
   2.使用 process.on('uncaughtException', function(err){...}); 来处理未被捕捉的错误。
   3.试用奶妈进程来启动你的程序,检测子进程的退出,然后自动重启该进程。比如 mother.js :


start();
function start()
{
    console.log('Mother process is running.');
    var ls = require('child_process').spawn('node', ['yourjsfile.js']);
    ls.stdout.on('data', function (data)
    {
        console.log(data.toString());
    });
    ls.stderr.on('data', function (data)
    {
        console.log(data.toString());
    });
    ls.on('exit', function (code)
    {
        console.log('child process exited with code ' + code);
        delete(ls);
        setTimeout(start,5000);
    });
}

    4.使用 nohup 让nodejs进程在后台运行。 比如运行"nohup node yourjsfile.js > /dev/null &"

完。

16410 read 16 comment(s)
NodeJS实现HTTP/HTTPS代理
2011-05-06

    身在天朝,难免会用到代理的时候。 比如在学校内网用代理免费上外网,在墙内用代理上404网站等。

    现在使用的代理大部分为HTTP和Socket代理。 Socket代理更底层,需要本地解析域名,而HTTP代理则是基于HTTP协议之上的,不需要本地解析域名。下面我讲讲HTTP(S)代理的设计思路以及NodeJS代码实现。

HTTP协议

    HTTP协议简单说来就是浏览器把一串字符串发送到目标服务器,然后把目标服务器返回回来的一串字符串显示给用户。

    浏览器发送的这串字符主要分为两个部分,一部分是头,里面包含目标服务器域名,当前请求的文件路径等信息。另一部分是正文,一般的GET请求没有正文。

    服务器返回来的字符串也分为头和正文。

HTTP代理原理

    HTTP代理需要做的事情就是接收浏览器发来的请求字符串,再从请求字符串的头部分找出浏览器请求的目标主机,然后直接把这串请求字符串发给目标主机,再把目标主机返回的数据发给浏览器。 “什么?就这么简单?” “呃。。是啊,但这还没完。。”

    现代浏览器一般都是默认采用HTTP/1.1版本,并且默认会发送Connection: keep-alive请求。 这些信息是写在请求的头部的,意思是通知目标服务器采用keep-alive技术继续处理后续的请求。 但是我们做的代理程序要想支持keep-alive是比较麻烦的。所以干脆就把这个篡改成Connection: close。 这样就可以保证浏览器请求的每个文件都会单独发送一个HTTP请求。

下面是NodeJS代码实现

 

var net = require('net');
var local_port = 8893;

//在本地创建一个server监听本地local_port端口
net.createServer(function (client)
{
    
    //首先监听浏览器的数据发送事件,直到收到的数据包含完整的http请求头
    var buffer = new Buffer(0);
    client.on('data',function(data)
    {
        buffer = buffer_add(buffer,data);
        if (buffer_find_body(buffer== -1return;
        var req = parse_request(buffer);
        if (req === falsereturn;
        client.removeAllListeners('data');
        relay_connection(req);
    });

    //从http请求头部取得请求信息后,继续监听浏览器发送数据,同时连接目标服务器,并把目标服务器的数据传给浏览器
    function relay_connection(req)
    {
        console.log(req.method+' '+req.host+':'+req.port);
        
        //如果请求不是CONNECT方法(GET, POST),那么替换掉头部的一些东西
        if (req.method != 'CONNECT')
        {
            //先从buffer中取出头部
            var _body_pos = buffer_find_body(buffer);
            if (_body_pos < 0_body_pos = buffer.length;
            var header = buffer.slice(0,_body_pos).toString('utf8');
            //替换connection头
            header = header.replace(/(proxy\-)?connection\:.+\r\n/ig,'')
                    .replace(/Keep\-Alive\:.+\r\n/i,'')
                    .replace("\r\n",'\r\nConnection: close\r\n');
            //替换网址格式(去掉域名部分)
            if (req.httpVersion == '1.1')
            {
                var url = req.path.replace(/http\:\/\/[^\/]+/,'');
                if (url.path != urlheader = header.replace(req.path,url);
            }
            buffer = buffer_add(new Buffer(header,'utf8'),buffer.slice(_body_pos));
        }
        
        //建立到目标服务器的连接
        var server = net.createConnection(req.port,req.host);
        //交换服务器与浏览器的数据
        client.on("data", function(data){ server.write(data); });
        server.on("data", function(data){ client.write(data); });

        if (req.method == 'CONNECT')
            client.write(new Buffer("HTTP/1.1 200 Connection established\r\nConnection: close\r\n\r\n"));
        else
            server.write(buffer);
    }
}).listen(local_port);

console.log('Proxy server running at localhost:'+local_port);


//处理各种错误
process.on('uncaughtException', function(err)
{
    console.log("\nError!!!!");
    console.log(err);
});



/**
* 从请求头部取得请求详细信息
* 如果是 CONNECT 方法,那么会返回 { method,host,port,httpVersion}
* 如果是 GET/POST 方法,那么返回 { metod,host,port,path,httpVersion}
*/
function parse_request(buffer)
{
    var s = buffer.toString('utf8');
    var method = s.split('\n')[0].match(/^([A-Z]+)\s/)[1];
    if (method == 'CONNECT')
    {
        var arr = s.match(/^([A-Z]+)\s([^\:\s]+)\:(\d+)\sHTTP\/(\d\.\d)/);
        if (arr && arr[1] && arr[2] && arr[3] && arr[4])
            return { method: arr[1], host:arr[2], port:arr[3],httpVersion:arr[4] };
    }
    else
    {
        var arr = s.match(/^([A-Z]+)\s([^\s]+)\sHTTP\/(\d\.\d)/);
        if (arr && arr[1] && arr[2] && arr[3])
        {
            var host = s.match(/Host\:\s+([^\n\s\r]+)/)[1];
            if (host)
            {
                var _p = host.split(':',2);
                return { method: arr[1], host:_p[0], port:_p[1]?_p[1]:80, path: arr[2],httpVersion:arr[3] };
            }
        }
    }
    return false;
}




/**
* 两个buffer对象加起来
*/
function buffer_add(buf1,buf2)
{
    var re = new Buffer(buf1.length + buf2.length);
    buf1.copy(re);
    buf2.copy(re,buf1.length);
    return re;
}

/**
* 从缓存中找到头部结束标记("\r\n\r\n")的位置
*/
function buffer_find_body(b)
{
    for(var i=0,len=b.length-3;i<len;i++)
    {
        if (b[i] == 0x0d && b[i+1] == 0x0a && b[i+2] == 0x0d && b[i+3] == 0x0a)
        {
            return i+4;
        }
    }
    return -1;
}

 

另外,可以用 "nohup node some.js > /dev/null &" 命令让nodejs程序在后台运行。

完。

40428 read 32 comment(s)
从Elance提现到国内银行的完美方法
2011-05-04

    我开始做自由职业已经有一个月左右了。主要是在elance.com上接项目。

    第一个项目做的是用jQuery做一个图片裁剪的功能,包括图片上传进度显示,两个比例的图片裁剪框。这个项目是100刀,elance扣了8.75刀的中介费,到手91.25刀。这个比例还是可以接受的。

     第二个项目是用nodejs做一个gtalk聊天机器人、一个facebook chat聊天机器人、一个msn聊天机器人。每个机器人200刀。在5天内搞完另外给400刀的bonus。结果我顺利在规定时间搞完,拿了1000刀。哈哈哈。

     钱到了Elance帐户上,怎么变成能够提现的人民币是个麻烦事情。我搜了网上很多文章,都说只有用moneybookers的服务最便宜。 于是我又搞了个moneybookers帐户。 那天突然发现如果成为elance的付费会员(最便宜的付费会员$10/月),就可以享受每月一次的免费电汇(wire transfer),超出一次以后貌似每笔要给25刀5刀手续费。于是就搞了个付费会员玩玩,不仅可以享受免费电汇,还有更多的点数和其他东西可以享受。付费会员只是多了一些Connect。免费会员一样每月又一次免费电汇的机会。那天试探提了200刀到我的中国银行活期一本通上,用的swiftcode是BKCHCNBJ570。过了大概4天,发现卡上真的有200美元,一分中间行费用都没扣。太TM爽了,这绝对是最便宜的提现途径,虽然每月只有一次机会。

     下一步就是去银行结汇,把美元转成人民币,这个步骤不知道要不要收手续费。

2012年10月更新:

      大家最好还是用中国银行。因为中国银行现在收到美元之后是自动上账(不知道其他地方,反正成都貌似都是),而其他一些银行(尤其是工商银行)收到美元后,要人工审核再上到你的账户上。人工审核这个时间就说不清楚了,快的话当天,慢的话无底限。。。关键是工行还要求我本人带身份证到我卡的开户行去办理!别人给我汇款还要我亲自去开户行办理接收手续!!

      还是中国银行好。在Elance上点击withdraw之后,2-3天Elance就会提醒说汇款手续已经办理。一般这个时候钱已经在中国银行账号上了,直接在网银就可以办理结汇,当然汇率要低一些。

      另外,Elance前段时间不知道搞什么飞机,直接提美元到美国以外的国家,每笔收25刀手续费。但是提其他币种就还是继续原来的价格(每月一次免费,超出5刀一次)。 Elance解释说是提倡在Elance完成币种转换,然后直接汇当地货币给你。我觉得可能elance想通过汇率差价赚钱?  操蛋的是提供选择的币种没有RMB! 不过我随便选了个欧元,就可以了。

BTW,欢迎加入Elance QQ群:162095216

完。

31213 read 38 comment(s)
Mac OS 上的各种ipv6配置命令
2011-04-11

IPv6 在Mac OS上是默认开启的。也可以用下面的命令手动开启或者关闭ipv6支持:

在所有网卡上开启ipv6:

ip6 -a

 

关闭ipv6:

ip6 -x

 

要打开router advertisements (RAs)可以用下面的命令:

sysctl -w net.inet6.ip6.accept_rtadv=1

 

关闭RAs的话,将上面的命令最后的数字改成0即可。

 

私有地址默认没有开启,可以用下面的命令开启:

sysctl net.inet6.ip6.use_tempaddr=1

 

在Mac OS上开启ISATAP隧道支持:

 

1、下载ISATAP client for Mac OS X

地址:http://www.momose.org/macosx/isatap.html

2、解压ISATAP client

 

cd /usr/local
sudo tar xfz ~/Downloads/macosx-isatap-*.tar.gz

 

3、更改权限

 

sudo chown -R root:wheel /usr/local/isatap
sudo chmod -R 644 /usr/local/isatap/isatap.kext

 

4、配置ISATAP

4.1 配置ist0和得到IPv4地址(你需要制定现在使用的网卡,比如en0)

 

sudo ./config-ist.sh en0

 

4.2 指定ISATAP router (111.111.111.111更换为你当地的ISATAP服务器地址)

 

sudo ./ifconfig ist0 isataprtr 111.111.111.111
sudo ./rtsold.sh &

 

4.3 设置路由表

 

sudo route delete -inet6 default

 

注:在执行上面命令之前可以用netstat -r查看ipv6路由表上是否有default这一项,没有则不用执行上面命令

 

sudo route add -inet6 default -interface ist0

 

4.4 启动IPv6

 

sudo ifconfig ist0 up

 

5、关闭IPv6

 

sudo ifconfig ist0 down

 

这样ISATAP就配置好了。

 

我的例子:

我在电子科技大学清水河校区,我们学校采用802.1X拨号上网。 我在拨号可以上网的前提下配置了RAs支持,即可正常上ipv6网站。 另外,我也可以通过配置ISATAP,使用隧道连接上ipv6。

完。

40621 read 5 comment(s)
还可以注册的3个字母的.ca域名
2011-03-11

    最近想注册个短一点的域名,搜了一下,发现.ca的域名还有很多3个字母的没有被注册。于是搞了个脚本统计了一下所有的3个字母的.ca域名。更新时间是2011年3月9号。以下是列表,总共3353个。有需要的同学可以找自己喜欢的注册。 推荐在godaddy注册,好处不用多说。

agz.ca
ajz.ca
akz.ca
awx.ca
axb.ca
axc.ca
axd.ca
axm.ca
axq.ca
axv.ca
ayq.ca
ayv.ca
ayw.ca

查看全文...  

40840 read 11 comment(s)
上一页 1 2 3 4 [5] 6 7 8 ...35 下一页
Copyright © Longbill 2008-2024 , Designed by EndTo , Powered by EndCMS