全书目录

第三十八篇:Phoenix 完全指南 —— 实时频道城邦宇宙

第四章:普通 HTTP 请求,像市民去大厅办一次事

2 分钟 564 字 第 723 / 962 个阅读单元

先别急着进 LiveView 和 Channels。
Phoenix 先是一套非常扎实的 HTTP 城邦。

一次普通请求的流转,大概像这样:

text
浏览器请求
   │
   ▼
Endpoint 城门
   │
   ▼
Plug 安检流水线
   │
   ▼
Router 分流到对应道路
   │
   ▼
Controller 办理业务
   │
   ▼
HTML/JSON 渲染
   │
   ▼
Response 回执出城

Phoenix 官方路由文档长期强调两件事:

  • 路由会被编译成高效的匹配结构
  • 每条路由还会生成 Phoenix.VerifiedRoutes 元数据

这意味着在 Phoenix 里,路由不是“运行时字符串碰碰运气”,而是编译期就尽量帮你发现坏链接和坏路径

看一个最小例子:

elixir
defmodule CityWeb.Router do
  use CityWeb, :router

  pipeline :browser do
    plug :accepts, ["html"]
    plug :fetch_session
    plug :fetch_live_flash
    plug :put_root_layout, html: {CityWeb.Layouts, :root}
    plug :protect_from_forgery
    plug :put_secure_browser_headers
    plug :fetch_current_scope_for_user
  end

  scope "/", CityWeb do
    pipe_through :browser

    get "/", PageController, :home
    get "/dispatches", DispatchController, :index
  end
end

上面这段你要这样理解:

  • pipeline :browser:入城默认安检线
  • plug:每一道安检闸机
  • scope "/":这一片城区
  • get "/dispatches":这条街的办事窗口是谁

Controller 看起来也很朴素:

elixir
defmodule CityWeb.DispatchController do
  use CityWeb, :controller

  alias City.Dispatch

  def index(conn, _params) do
    dispatches = Dispatch.list_dispatches(conn.assigns.current_scope)
    render(conn, :index, dispatches: dispatches)
  end
end

对应 HTML 层:

elixir
defmodule CityWeb.DispatchHTML do
  use CityWeb, :html

  def index(assigns) do
    ~H"""
    <Layouts.app flash={@flash} current_scope={@current_scope}>
      <section>
        <h1>今日调度公报</h1>

        <ul>
          <li :for={dispatch <- @dispatches}>
            {dispatch.title} - {dispatch.status}
          </li>
        </ul>

        <.link href={~p"/live/dispatches"}>进入实时调度台</.link>
      </section>
    </Layouts.app>
    """
  end
end

这里有三个 Phoenix 味道很重的点:

  1. render(conn, :index, ...) 不是去找“古早 view 魔法”,而是去调用对应 HTML 模块里的函数组件模板。
  2. ~H 是 HEEx,不只是字符串模板,而是 HTML 感知模板。
  3. ~p"/live/dispatches" 是编译期校验过的路径,不是裸字符串。

所以 Phoenix 的 HTTP 层很像一座秩序极好的政务大厅:
路怎么走,窗口谁办,公文怎么渲染,都是清楚的。