本文基於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之道多半是講「道」,而個人「道」是道路的「道」。哈哈哈,總感受一不當心起了個大名字。