Cowboy 用户指南 (十八) - REST流程图

REST 流程图

本章将通过许多不同的图来解释REST处理程序状态机。

请求可以遵循四种主要路径。一个用于方法OPTIONS;一个用于方法GET和HEAD;一为PUT、POST、PATCH方法;一个用于方法DELETE。

所有路径都从“开始”图开始,如果资源存在,那么除了选项路径之外的所有路径都会经过“内容协商”图,或者可以选择的“条件请求”图。

红色方块代表另一个图表。浅绿色方块表示响应。其他方块可能是Cowboy自己应答的一个问题或回调。如果回调函数未定义,绿色箭头往往指示默认行为。值旁边的星号表示该值是描述性的,而不是精确的。

开始

所有请求都从这里开始.

REST starting flowchart

连续调用一系列回调函数来执行对服务、请求行和请求报头的常规检查。

如果有请求主体,则预期不会为这些步骤中的任何一个接收到请求主体。只有在“PUT, POST和PATCH方法”图的末尾,当所有条件都满足时,才会处理它。

known_methods和allowed_methods回调函数返回一个方法列表。Cowboy然后检查请求方法是否在列表中,否则停止。

可以使用is_authorized回调函数检查对资源的访问是否被授权。也可以根据需要执行身份验证。当拒绝授权时,来自回调的返回值必须包括一个适用于所请求资源的问题,该问题将在www-authenticate报头中发送回客户机。

当请求方法是OPTIONS时,紧跟着这个图的是“OPTIONS方法”图,否则紧跟着的是“内容协商”图。

OPTIONS 方法

此图仅适用于OPTIONS 请求。

REST OPTIONS method flowchart

options 回调可用于添加有关资源的信息,例如所提供的媒体类型或语言;允许的方法;任何额外的信息。也可以设置响应主体,但不应期望客户端读取响应主体。

如果没有定义options回调,Cowboy将发送一个默认包含允许方法列表的响应。

内容协商

此图适用于除选项之外的所有请求方法。它在“开始”图完成后立即执行。

REST content negotiation flowchart

这些步骤的目的是确定发送回客户机的适当表示。

请求可以包含任何accept报头;accept - language报头;或者accept-charset报头。出现时,Cowboy将解析报头,然后调用相应的回调函数来获取为该资源提供的内容类型、语言或字符集的列表。然后它会根据请求自动选择最佳匹配。

如果没有定义回调,Cowboy将选择客户端喜欢的content-type、language 或charset 。

content_types_provided也会为它接受的每个content-type返回回调的名称。这个回调函数只会在“GET和HEAD方法”图的最后被调用,当所有的条件都满足的时候。

所选的内容类型、语言和字符集作为元值保存在Req对象中。如果您手动设置了响应主体(例如,伴随着错误代码),则应该使用适当的表示。

这个图紧接着是“GET和HEAD方法”图,“PUT, POST和PATCH方法”图,或者“DELETE方法”图,这取决于方法。

GET 和 HEAD 方法

此图仅适用于GET和HEAD请求。

有关第二个步骤的描述,请参见“条件请求”图。

REST GET/HEAD methods flowchart

当资源存在,且条件步骤成功时,可以检索资源。

Cowboy通过首先检索关于表示的元数据来准备响应,然后调用ProvideResource回调。这是为从content_types_provided返回的每个content-type定义的回调函数。这个回调函数返回将被发送回客户端的主体,如果体必须被流化,则返回一个函数的主体。

当该资源不存在时,Cowboy将查明该资源以前是否存在,如果存在,它是否被移动到其他地方,以便将客户端重定向到新的URI。

如果资源确实被移动了,那么moved_permanent和moved_temporary回调函数必须返回资源的新位置。

PUT, POST 和 PATCH 方法

此图仅适用于PUT、POST和PATCH请求。

有关第二个步骤的描述,请参见“条件请求”图。

REST PUT/POST/PATCH methods flowchart

当资源存在时,首先执行条件步骤。当成功并且方法是PUT,Cowboy将调用is_conflict回调函数。这个函数可以用来防止潜在的竞争条件,例如通过锁定资源。

然后这三个方法都达到了content_types_accepted步骤,我们将在几段中描述这个步骤。

当资源不存在,并且方法是PUT时,Cowboy将检查冲突,然后进入content_types_accepted步骤。对于其他方法,Cowboy将查明该资源以前是否存在,如果存在,是否被转移到其他地方。如果资源确实不存在,方法是POST并且allow_missing_post的调用返回true,那么Cowboy将继续执行content_types_accepted步骤。否则,请求处理将在那里结束。

如果资源确实被移动了,那么moved_permanent和moved_temporary回调函数必须返回资源的新位置。

content_types_accepted返回它所接受的content-type列表,以及每个content-type的回调名称。Cowboy将选择适当的回调来处理请求主体并调用它。

这个回调函数可以返回三个不同返回值中的一个。

如果在处理请求主体时发生错误,则必须返回false, Cowboy将发送适当的错误响应。

如果方法是POST,那么您可以返回true,并提供创建资源的URI。这对于为集合编写处理程序特别有用。

否则,返回true表示成功。Cowboy将选择要发送的适当响应,这取决于是否创建了资源,而不是修改了资源,以及响应中位置报头或主体的可用性。

DELETE 方法

此图仅适用于DELETE 请求。

有关第二个步骤的描述,请参见“条件请求”图。

REST DELETE method flowchart

当资源存在,且条件步骤执行成功时,可以删除该资源。

删除资源需要两个步骤。首先执行回调函数delete_resource。使用这个回调来删除资源。

由于资源可能被缓存,所以您还必须删除系统中该资源的所有缓存表示。不过,这个操作可能需要一段时间,因此您可能会在它完成之前返回。

然后Cowboy将调用delete_completed回调函数。如果您知道资源已经从您的系统中(包括从缓存中)完全删除,那么您可以返回true。如果任何疑问仍然存在,则返回false。Cowboy将默认为真。

最后,Cowboy检查是否设置了响应主体,并根据此情况发送适当的响应。

当该资源不存在时,Cowboy将查明该资源以前是否存在,如果存在,它是否被移动到其他地方,以便将客户端重定向到新的URI。

如果资源确实被移动了,那么moved_permanent和moved_temporary回调函数必须返回资源的新位置。

条件请求

此图适用于除OPTIONS之外的所有请求方法。当资源存在时,它会在resource_exists回调之后执行。

REST conditional requests flowchart

请求将会变成条件当它包含 if-match报头,if-unmodified-since报头;if-none-match报头;if-modified-since报头中的任何一个时。

如果条件失败,请求立即结束,不需要对资源进行任何检索或修改。

根据需要调用generate_etag和last_modified。Cowboy只会调用它们一次,然后缓存结果供后续使用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 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、付费专栏及课程。

余额充值