本文基于Phoenix1.3,但请求的处理流程跟1.2基本一致,只是模块的命名和目录结构有所差别。css
简单介绍,phoenix是一个网站框架,本质就是http请求处理。这篇文章主要就是讲一个请求,在结果回到用户以前,走过了哪些路。经过这种方式,介绍phoenix框架中各个组成部分(包括endpoint、routing、controller、view、template、channel)。仅做phoenix框架入门之用,未涉及底层cowboy框架。html
上图(我很丑也并不温柔,手残做者 ==! ):web
以上是基本上全部的请求走的路,绿色部分表示正儿八经的请求,其余的杂色则表示链接、加入频道等前期准备工做。api
请求主要分三类:静态资源、动态资源或http请求、websocket请求。其中前两类均为一次性链接,每次请求均启动一个新进程进行处理,回复完成后会话结束。而websocket方式则是长期存在的链接,可进行双向通讯。websocket
静态资源即不用通过任何处理,能够直接返回给用户的资源。如图,静态资源进入endpoint即返回。在endpoint.ex中有下面这段,这一段就定义了能够直接返回给用户的静态资源,资源放在priv/static/目录下。这类资源直接以文件形式返回给用户,不通过后续处理流程。app
plug Plug.Static, at: "/", from: :my_app, gzip: false, only: ~w(css fonts images js index.html)
这部分指的是非web_socket的请求,一般是须要进行必定的处理和渲染才能返回给客户端的资源或数据。在图中的下半部分有所展现,主要涵盖router、controller、view、template部分。框架
1.消息首先通过endpoint进行一些初始化处理,如解码等,endpoint就是一个流水线,流水线的最后一步走入router中进行路由。socket
2.在router中也能够定义不一样的流水线,根据请求路径和请求方式,对请求方进行权限验证或其余自定义的数据初始化。全部验证经过后,会根据定义的路由,分发进入不一样的controller中进行最终处理。函数
3.controller是实际处理请求的地方,服务端请求处理逻辑所在处。在controller中处理完成后,能够调用不一样的接口,直接回复给用户(如: text(conn, "ok") ),或者调用渲染方法(如:render(conn, "homePage.html", param: param) ),并传入返回参数。网站
4.渲染主要在与controller的前缀相同的view中进行,若是是文件模板,则会从 templates/xyz 目录下找对应的模板,而后用传入参数进行渲染。渲染完后发送给用户。
这部分是图中的上半部分,主要涵盖socket、channel部分。Phoenix框架的websocket中有一个channel的概念,可围绕channel作消息转发、广播等,甚至也能够作api请求。
加入socket的url,在endpoint.ex中有定义,以下:
socket "/socket", AppWeb.XyzSocket
即,经过websocket链接 www.example.com/socket 可对应到AppWeb.XyzSocket模块进行链接处理。处理链接的是新生的一个进程,该进程调用AppWeb.XyzSocket模块的 connect/2 函数进行初始化,该函数返回:error则表示链接失败,{:ok, socket}则表示链接成功。失败的话进程退出,成功则进程保留,用以用户消息的收发。此过程为图中红色线所示。
在链接socket的时候,AppWeb.XyzSocket模块中会定义可链接的channel及对应处理模块,以下:
channel "abc:*", AppWeb.AbcChannel
当用户加入"abc:"开头的channel时,会启动一个channel进程,调用 AppWeb.AbcChannel.join/2 函数进行处理,该函数中可作一些权限验证和频道的初始化。若是该函数返回{:ok, socket}则表示加入成功,进程保留为该用户在此频道中的数据交流之用。返回{:error, reason}则加入失败,进程退出。此过程为图中蓝色线所示。
用户加入channel后,可往channel发送消息(如图中上半部分绿线流程),channel也能够主动往客户端推送消息(如图中橙色线所示)。如图所示,其消息收发都是要通过socket进程,不过socket进程的转发属于隐形的过程,写代码时涉及很少。
用户向channel发送消息时,会在对应的channel进程调用 AppWeb.AbcChannel.handle_in/2 函数进行消息处理。处理完后函数返回 {:reply, reply, socket} 便可把reply返回给用户(底层经由socket进程)。
channel经过调用 push 或 broadcast 接口(详见官方文档)能够主动向用户发送消息。
所谓的XX之道多半是讲“道”,而个人“道”是道路的“道”。哈哈哈,总感受一不当心起了个大名字。