鸿 网 互 联 www.68idc.cn

当前位置 : 服务器租用 > 编程语言开发 > erlang > >

Cowboy 源码分析(十八)

来源:互联网 作者:佚名 时间:2012-11-15 13:43
在上一篇中,我们整理了下函数定义如下: %% Only send an error reply if there is no resp_sent message. -spec error_terminate(cowboy_http:status(), #state{}) - ok.error_terminate(Code, State =#state{socket=Socket, transport= Transport,onrespo

  在上一篇中,我们整理了下函数定义如下:

%% Only send an error reply if there is no resp_sent message. -spec error_terminate(cowboy_http:status(), #state{}) -> ok. error_terminate(Code, State=#state{socket=Socket, transport=Transport, onresponse=OnResponse}) -> receive {cowboy_http_req, resp_sent} -> ok after 0 -> _ = cowboy_http_req:reply(Code, #http_req{ socket=Socket, transport=Transport, onresponse=OnResponse, connection=close, pid=self(), resp_state=waiting}), ok end, terminate(State). -spec terminate(#state{}) -> ok. terminate(#state{socket=Socket, transport=Transport}) -> Transport:close(Socket), ok.

  这个函数,仅仅是给客户端一个错误答复。Code是代表返回的HTTP状态码,具体每个值代表什么意思,大家可以参考下维基百科的HTTP状态码 这个需要大家了解下HTTP协议的相关内容。真的很有必要,了解底层的一些协议。建议大家买几本相关的书看看。

  好了,回到逻辑本身,这里有个知识点,摘自《Erlang程序设计》 109页:

  超时时间为0的receive  

   一个超时时间为0的语句会立即触发一个超时,但在此之前,系统会尝试对邮箱进行模式匹配,我们可以利用这个特性来定一个flush_buffer函数,它可以完全清空进程邮箱中的所有消息:

  flush_buffer() ->     receive       _Any ->         flush_buffer()     after 0 ->       true     end.

  好了,回到逻辑中,这个函数会检查进程的邮箱中是否存在 {cowboy_http_req, resp_sent} 消息,如果存在,则返回 ok,紧接着马上触发一个超时,我们来看下,超时中的处理代码:

_ = cowboy_http_req:reply(Code, #http_req{ socket=Socket, transport=Transport, onresponse=OnResponse, connection=close, pid=self(), resp_state=waiting}), ok

  这里调用 cowboy_http_req:reply/2 函数,香港服务器租用,并且忽略返回值,紧接着返回 ok,这里我们来重点看下这个函数:

%% @equiv reply(Status, [], [], Req) -spec reply(cowboy_http:status(), #http_req{}) -> {ok, #http_req{}}. reply(Status, Req=#http_req{resp_body=Body}) -> reply(Status, [], Body, Req). %% @equiv reply(Status, Headers, [], Req) -spec reply(cowboy_http:status(), cowboy_http:headers(), #http_req{}) -> {ok, #http_req{}}. reply(Status, Headers, Req=#http_req{resp_body=Body}) -> reply(Status, Headers, Body, Req). %% @doc Send a reply to the client. -spec reply(cowboy_http:status(), cowboy_http:headers(), iodata(), #http_req{}) -> {ok, #http_req{}}. reply(Status, Headers, Body, Req=#http_req{socket=Socket, transport=Transport, version=Version, connection=Connection, method=Method, resp_state=waiting, resp_headers=RespHeaders}) -> RespConn = response_connection(Headers, Connection), ContentLen = case Body of {CL, _} -> CL; _ -> iolist_size(Body) end, HTTP11Headers = case Version of {1, 1} -> [{<<"Connection">>, atom_to_connection(Connection)}]; _ -> [] end, {ReplyType, Req2} = response(Status, Headers, RespHeaders, [ {<<"Content-Length">>, integer_to_list(ContentLen)}, {<<"Date">>, cowboy_clock:rfc1123()}, {<<"Server">>, <<"Cowboy">>} |HTTP11Headers], Req), if Method =:= 'HEAD' -> ok; ReplyType =:= hook -> ok; -> case Body of {_, StreamFun} -> StreamFun(); _ -> Transport:send(Socket, Body) end end, {ok, Req2#http_req{connection=RespConn, resp_state=done, resp_headers=[], resp_body= <<>>}}.

  不管是 reply/2,还是reply/3最后都是调用reply/4函数,这个函数是给客户端发一个回复,代码量相对多些,我们来详细看下:

  我们看下,函数参数:参数Status就是Code,也就是HTTP状态码,Headers为空列表 [],Req=#http_req{resp_body=Body},这里的Body为默认值 resp_body  = <<>>,Sokcet的值为连接到服务器的连接,Transport 为cowboy_tcp_transport,Version 值为 {1,1},其他:Connection = keepalive,Method = 'GET',RespHeaders = [],网站空间,有些值是默认值,大家可以看下记录的定义。

  来看具体逻辑:

  RespConn = response_connection(Headers, Connection), 这里调用cowboy_http_req:response_connection/2函数,函数代码如下:

网友评论
<