最近做了一个node.js的中间层项目,为了极致的性能,我们打算尽量少用第三方类库,连HttpServer我们都用原生的来做,没有使用Expressjs。
1、request的body拼接的坑
这个是老生常谈的问题,一般写出如下代码的同学,都是会被喷是Node.js初学者。
1 | http.request({ |
为什么上面的代码会被喷?因为chunk是bufer类型,直接进行toString拼接,对于二进制的响应,可能会存在问题,特别是中文会被截断。于是我们就改成了下面这个代码:
1 | http.request({ |
然而事与愿违,body.join(‘’)在拼接buffer块的时候也会存在先toString()再拼接的,所以真确的代码应该如下:
1 | http.request({ |
另外,Node.js在utf-8字节不正确的时候,会把utf-8字节改成\uFFFD
,当出现类似?
号的乱码时,就需要注意了,是因为某一个utf-8字节缺失导致的。
2、两次callback调用的坑
当我们初次调试我们代码的时候,发生了一个诡异的问题,callback被莫名其妙的调用了两次,我们还是上伪代码:
1 | const reqToRemote = (opt, cb)=>{ |
初步看上去,代码似乎没啥问题,每个callback后面都根了return,保证callback只会被调用一次,没有理由callback会被调用两次呢。但是当cb传入的函数,本身throw error的情况呢?
也就是说,JSON.parse并没有发生异常,而是cb函数本身抛出了同步
的异常,这时候try就捕获了错误,同时执行了catch代码块的cb,这个时候我们的callback就被执行了两次。
3、原生reqeust的timeout
我们在代码初次调试的时候,发现无论reqeust的timeout设置多久,都没有出现超时的情况,我们初次写的代码如下:
1 | const req = http.request({ |
后来翻阅node.js的api文档,发现原生的http.request函数里的timeout,仅仅是socket的连接超时,原文如下:
A number specifying the socket timeout in milliseconds. This will set the timeout before the socket is connected.
所以我们需要对socket连接之后设置timeout来进行请求的超时限制,伪代码如下:
1 | req.once('socket', (s: Socket) => { |
但是这样的做法,效果是可以,可惜会导致正常响应之后,req的error事件触发,这里我们就做了一个小动作,保证了req的回调只执行一次。