Erlang cowboy http request生命周期
翻译自:
http://ninenines.eu/docs/en/cowboy/1.0/guide/http_req_life/
request的生命周期
本章解释服务器response之前的http request的步骤,以及cowboy实现的细节。
Request/response
正如你了解到的,HTTP客户端连接到服务器,发送资源请求(request),服务器发送响应(response),其中包含可以获取到的资源。
在服务器发送资源之前,它需要一些步骤去读请求,找出资源,准备发送资源,还包括其他关联的操作,如写日志等。
在cowboy中,请求按下图路由:
本图显示了默认的处理中间件(middlewares),可以被设置成不同的方式。深绿色(双框)标明了用户可以插入(hook)自己实现的代码点。浅绿色是cowboy代码,可以根据需要设置。
acceptor
是服务器的一部分,它接受连接,然后创建一个Erlang进程处理它。
parser接着开始读取
socket连接,当请求到来时处理之,直到socket关闭。
在请求的整个周期中,可以在多个地方返回响应。如果cowboy不能解析请求,它会结束处理返回错误。如果路由router不能找到资源,它会返回not found错误。你自己的代码在任何时候都可以返回响应。
当响应被发送,你可以选择修改它,或者在onresponse的回调中实现代码
。默认,响应被直接发送给客户端。
And then?
具体的行为依赖采用的协议。
HTTP/1.0 仅仅能一个连接处理一个请求,因此Cowboy在发送响应之后立即关闭连接。
HTTP/1.1 允许客户端请求服务端并保持这个连接。这个机制下面会说明。
SPDY 用于在同一个连接上发送多个异步请求,详见下面。
Keep-alive (HTTP/1.1)
在HTTP/1.1协议中,连接可以一直被打开,并连续发生请求。这种机制称为keep-alive
。
当客户端发送请求到服务端,它包含一个头,标识是否需要保持连接打开状态。服务端可以接受,也可以不接受,同样在响应的头部中返回它的选择。
对 HTTP/1.1 requests,Cowboy自动在所有响应中包含这个头部。如果你愿意也可关闭socket连接。 当 Cowboy 看到你设置了connection: close
头,它不会覆盖你的设置,当响应被发送,就会关闭连接。
下面的代码强迫Cowboy关闭连接:
{ok, Req2} = cowboy_req:reply(200, [ {<<"connection">>, <<"close">>}, ], <<"Closing the socket in 3.. 2.. 1..">>, Req).
Cowboy在同一个连接上仅仅接受一定数目的请求,默认是100个请求。当启动一个HTTP监听时,这个数目可以按下面的方法改变(max_keepalive
):
cowboy:start_http(my_http_listener, 100, [{port, 8080}], [ {env, [{dispatch, Dispatch}]}, {max_keepalive, 5} ]).
Cowboy通过为所有请求重用同一个进程来实现保活keep-alive。这样Cowboy就可以节省内存。这种方式能够起作用,因为多数代码对后续请求没有副作用。但是同时也意味如果你的代码存在副作用,就必须做清理工作,terminate/3
函数就是干这个的。
Pipelining (HTTP/1.1)
HTTP是一种顺序化的协议,客户端发送请求,然后等待服务端响应。由于sockets的工作模式,http不会阻止客户发送更多的请求,不会强迫客户等待响应。服务器仍然按顺序地处理请求,按同样的次序返回响应。
这种机制称为pipelining。当客户在一个时间内请求更多的资源时能减少延时,例如,这种方式被浏览器请求静态文件时使用。
这种模式被服务器自动处理。
异步请求 requests (SPDY)
在SPDY,客户可以在任何时间发送请求,服务也是可以在任何时候返回响应。这意味着客户端不必等待请求被完全发送就可以发另一个请求,这样交织发送请求就成为可能。同样也适合服务端。响应也可以用不同的次序发送。
因为请求和响应是完全异步的,Cowboy为每个请求创建一个新的进程,这些进程被另一个处理连接的进程管理。SPDY服务也可以决定是否在请求之前发送资源给客户,这种方式对发送与HTML页面关联的静态文件特别有用,因为减少了响应延时。但是,当前Cowboy不支持这种机制。