问题
项目的前端是vue,node端使用Express做中间层,后端告诉我们有个http请求需要耗时很久,说后续会优化,先应急处理(😅)。
在debug的过程中,发现一直出现timeout的情况,检查了客户端请求的设置,没有特殊限制请求的超时,然后想到会不会是服务端的问题,立刻翻查了Node的API
nodejs.org/dist/latest…
由文档中我们可以知道,Node服务器对每个客户端请求的默认连接时长是2min,在这个时间内,服务器没有发送响应信息,客户端的连接会被重置。
探讨
我们先创建个node服务器实例。
|
http.createServer创建一个HTTP服务器server, 在这个服务器中,我们添加了一个HTTP客户端请求监听函数,该函数包括两个参数:req和res。其中,req是一个客户端请求对象包含了客户端的请求信息,它是一个http.IncomingMessage实例。而res是服务器响应对象,它是一个http.ServerResponse实例,服务器处理完用户请求后通过访问对象向客户端返回响应信息
服务端的超时设置
对于一个http服务器来说,我们可能会设置以下两种类型的超时:
用户请求的超时
即上例中http.IncomingMessage实例-req
用户请求时间过长,会导致服务器停留在一个用户请求的接收状态,从而阻碍其他用户请求的进入。
服务器响应的超时
即上例中http.ServerResponse实例-res
服务器响应时间过长,会导致用户长时间接收不到服务器响应信息,影响用户体验和其他用户请求的处理
解决方案
Node.js HTTP服务器设置超时使用setTimeout()方法。
http.Server、http.IncomingMessage和http.ServerResponse中都有一个setTimeout()方法。server.setTimeout()会设置所有用户请求和服务器响应的超时时间,而req.setTimeout()只能针对本次请求超时时间进行设置,res.setTimeout()只能针对本次请求的服务器响应超时时间进行设置。我们可以像下面这样在HTTP服务端设置超时:
将所有的用户请求和服务器响应超时时间设置为5秒:
|
|
对于某一个比较耗时的用户请求, 我们将用户请求超时时间设置为20秒:
|
|
对于一个需要在服务器进行较长时间处理用户请求, 我们将服务器响应的超时时间设置为10秒:
|
|
使用Express.js中间件设置超时
Express.js提供了强大的中间件机制,利用这一机制我们可以更为灵活的设置HTTP服务器超时时间。
如,我们可以在app.js文件中添加如下处理程序,分别设置请求和服务器响应的超时时间,当然也可以只设置请求超时或服务器响应超时时间:
|
对比较某一个比较耗时的用户请求,或需要较多响应时间才能完成处理的请求,我们可以其路由处理方法或路由中间件中单独设置超时时间:
|
使用Koa中间件设置超时,我们可以设置服务器响应的时间。
|
拓展
处理了服务端的请求响应设置后,问题还没有结束,如果前端项目部署有使用了nginx做proxy代理,那就需要在nginx处修改, 修改连接超时限制。
|
简单说明下:
proxy_connect_timeout 默认值 60s
这个指令设置与upstream server的连接超时时间,如果你的upstream服务器起来了,但是hanging住了(例如,没有足够的线程处理请求,所以把你的请求放到请求池里稍后处理),那么这个声明是没有用的,由于与upstream服务器的连接已经建立了。
proxy_read_timeout 默认值 60s
该指令设置与代理服务器的读超时时间。它决定了nginx会等待多长时间来获得请求的响应。这个时间不是获得整个response的时间,而是两次reading操作的时间。
proxy_send_timeout 默认值 60s
这个指定设置了发送请求给upstream服务器的超时时间。超时设置不是为了整个发送期间,而是在两次write操作期间。如果超时后,upstream没有收到新的数据,nginx会关闭连接。
最后
Node的服务器在处理连接超时很灵活,这种响应时间较长的请求还是要尽量避免,尽管开了几个实例,当并发量一多,会占用很多网络资源。