Cowboy 用户指南 (十三) - Reading the request body

读取请求主体

可以使用Req对象读取请求主体。

Cowboy不会试图读取主体,除非有人要求。您需要调用主体读取函数来检索它。

Cowboy不会缓存主体,因此只能读取一次。

但是,你不需要阅读它。如果有主体存在但没有被读取,Cowboy会取消或跳过它的下载,这取决于协议。

Cowboy提供了一些函数来读取主体原始信息,并从urlencoded或多部分主体中读取和解析。后者在它自己的章节中有讨论。

请求主体的存在

并不是所有的请求都伴随着一个主体。你可以用这个函数来检查请求体是否存在:

cowboy_req:has_body(Req).

如果存在主体则返回true;否则错误。

在实际操作中,很少使用这个函数。当方法是POST、PUT或PATCH时,应用程序通常需要请求主体,它应该尝试直接读取请求主体。

请求主体的长度

你可以得到主体的长度:

Length = cowboy_req:body_length(Req).

注意,长度可能不会提前知道。在这种情况下,undefined将被返回。这种情况会发生在HTTP/1.1的分块传输编码中,或者HTTP/2没有提供内容长度时。

一旦主体被完全读取,Cowboy将更新Req对象中的主体长度。当完全读取主体后试图调用这个函数时,将总是返回一个长度。

读取主体

你可以通过一个函数调用来读取整个函数主体:

{ok, Data, Req} = cowboy_req:read_body(Req0).

当完整读取主体时,Cowboy返回一个ok元组。

默认情况下,Cowboy将尝试读取最多8MB的数据,持续15秒。一旦Cowboy读取了至少8MB的数据,或者在15秒的时间结束时,该调用将返回。

这些值可以自定义。例如,在5秒内只读1MB:

{ok, Data, Req} = cowboy_req:read_body(Req0,
    #{length => 1000000, period => 5000}).

你也可以禁用长度限制:

{ok, Data, Req} = cowboy_req:read_body(Req0, #{length => infinity}).

这使得函数等待15秒,并返回在这段时间内到达的任何内容。对于面向公众的应用程序,不建议这样做。

这两个选项可以有效地用来控制请求主体的传输速率。

流主体

当函数体太大时,第一次调用将返回一个更大的元组,而不是ok。您可以再次调用该函数来读取主体的更多内容,每次读取一个数据块。

read_body_to_console(Req0) ->
    case cowboy_req:read_body(Req0) of
        {ok, Data, Req} ->
            io:format("~s", [Data]),
            Req;
        {more, Data, Req} ->
            io:format("~s", [Data]),
            read_body_to_console(Req)
    end.

也可以使用长度和周期选项。每次call都要传递这些信息。

读取表单的urlencoded主体

Cowboy提供了一个方便的函数来读取和解析作为application/x-www-form-urlencoded发送的主体。

{ok, KeyValues, Req} = cowboy_req:read_urlencoded_body(Req0).

这个函数返回一个键值列表,就像函数cowboy_req:parse_qs/1一样。

这个函数的默认值是不同的。Cowboy的读取时间可达64KB,最长可达5秒。它们可以被修改:

{ok, KeyValues, Req} = cowboy_req:read_urlencoded_body(Req0,
    #{length => 4096, period => 3000}).
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是一个简单的使用erlang的cowboy框架编写的websocket聊天室代码示例。 ```erlang %% 定义路由和处理函数 -module(chat_router). -behaviour(cowboy_router). -export([init/3]). -export([routes/2]). init(_Transport, _Req, _Opts) -> {ok, [], undefined}. routes(_Req, _State) -> {[ {'_', [ {"/websocket", cowboy_websocket_handler, [ {callback, chat_handler}, {origin, "*"} ]} ]} ], _Req, _State}. %% 定义websocket处理函数 -module(chat_handler). -behaviour(cowboy_websocket_handler). -export([init/3]). -export([websocket_init/3]). -export([websocket_handle/3]). -export([websocket_info/3]). -export([websocket_terminate/3]). init(_TransportName, Req, _Opts) -> {ok, Req, undefined}. websocket_init(_TransportName, Req, _Opts) -> {cowboy_websocket, Req, undefined}. websocket_handle({text, Message}, Req, _State) -> %% 处理收到的文本消息 cowboy_websocket:broadcast(Message, Req), {ok, Req, undefined}; websocket_handle(_Data, Req, _State) -> {ok, Req, undefined}. websocket_info({join, _Pid, _Ref}, Req, _State) -> %% 处理新用户加入聊天室 cowboy_websocket:broadcast("New user joined", Req), {ok, Req, undefined}; websocket_info({leave, _Pid, _Ref}, Req, _State) -> %% 处理用户离开聊天室 cowboy_websocket:broadcast("User left", Req), {ok, Req, undefined}; websocket_info(_Info, Req, _State) -> {ok, Req, undefined}. websocket_terminate(_Reason, Req, _State) -> {ok, Req, undefined}. ``` 以上代码定义了一个路由模块`chat_router`,其中`routes/2`函数指定了处理`/websocket`路径的`cowboy_websocket_handler`处理函数,并将其回调函数指定为`chat_handler`。`chat_handler`模块中的`websocket_handle/3`函数用于处理接收到的文本消息,并使用`cowboy_websocket:broadcast/2`函数将消息广播给所有连接的客户端。`websocket_info/3`函数用于处理新用户加入和离开聊天室的事件,同样使用`cowboy_websocket:broadcast/2`函数将事件广播给所有连接的客户端。 您可以将以上代码保存为`chat.erl`文件,并使用cowboy框架启动websocket服务器,例如: ```erlang %% 启动websocket服务器 -module(chat). -behaviour(application). -export([start/2, stop/1]). start(_Type, _Args) -> Dispatch = cowboy_router:compile([ {'_', [{"/websocket", chat_handler, []}]} ]), {ok, _} = cowboy:start_clear(http, [{port, 8080}], #{env => #{dispatch => Dispatch}}), chat_sup:start_link(). stop(_State) -> ok. ``` 以上代码定义了一个应用模块`chat`,其中`start/2`函数启动了一个cowboy服务器,监听8080端口,并将路由配置为处理`/websocket`路径,使用`chat_handler`处理函数。您可以将以上代码保存为`chat_app.erl`文件,并使用`rebar3`编译和启动应用程序: ```sh $ rebar3 compile $ rebar3 shell ``` 在erlang shell中,您可以使用以下命令连接到websocket服务器并发送消息: ```erlang %% 连接到websocket服务器 1> {ok, Conn} = websocket:connect("ws://localhost:8080/websocket"). {ok,{websocket,#Port<0.7>,<0.198.0>}} %% 发送消息 2> websocket:send_text(Conn, "Hello, World!"). ok ``` 在另一个erlang shell中,您可以使用以下命令连接到相同的websocket服务器并接收消息: ```erlang %% 连接到websocket服务器 1> {ok, Conn} = websocket:connect("ws://localhost:8080/websocket"). {ok,{websocket,#Port<0.7>,<0.203.0>}} %% 接收消息 2> websocket:recv_text(Conn). "New user joined" 3> websocket:recv_text(Conn). "Hello, World!" ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值