Phoenix Elixir Web 框架

FreeGuideOnline 18阅读 2026-07-11

什么是 Phoenix?

Phoenix 是用 Elixir 语言编写的 Web 开发框架,它基于久经考验的 Erlang VM(BEAM),天生具备高并发、低延迟与容错能力。Phoenix 借鉴了 Ruby on Rails 等框架的“约定优于配置”理念,同时保留了函数式编程的优点,让你能用简洁的代码构建实时、高性能的 Web 应用。

如果你追求流畅的开发体验,又需要支撑百万级并发连接,Phoenix 是目前最值得投入学习的技术之一。

为什么选择 Phoenix?

  • 高性能与高并发:运行在 BEAM 虚拟机上,轻松处理海量 WebSocket 连接和请求。
  • 实时功能内建:通过通道(Channels)和 Presence 实现实时通信,无需引入第三方库。
  • 函数式、不可变数据:Elixir 的模式匹配与不可变数据让代码易于推理和测试。
  • 强大的工具链:Mix 构建工具、Ecto 数据库层、LiveView 服务端渲染交互组件等开箱即用。
  • 容错与分布式:基于 Erlang/OTP 的监督树机制,生产环境更健壮。

环境准备

开始之前,确保本地已安装以下工具:

  1. Elixir (建议 1.14 或以上)
    访问 elixir-lang.org 根据操作系统进行安装。
  2. Erlang/OTP (通常与 Elixir 一起安装)
  3. PostgreSQL (Phoenix 默认数据库)
    确保 PostgreSQL 服务已启动。
  4. Node.js (用于编译前端资源,新版 Phoenix 也已支持 esbuild/tailwind 等更轻量的方式)

安装完成后,可运行以下命令验证:

elixir --version
mix --version
npm --version   # 如果需要前端依赖

安装 Phoenix 项目生成器

使用 Mix 安装 phx_new 归档:

mix archive.install hex phx_new

该命令会获取最新的 Phoenix 项目生成器,之后你就可以在任何目录下执行 mix phx.new 创建项目。

创建你的第一个 Phoenix 应用

在终端中运行:

mix phx.new hello_phoenix --database postgres
cd hello_phoenix

参数说明:

  • hello_phoenix 为应用名称,会创建同名目录。
  • --database postgres 指定使用 PostgreSQL 作为数据库(也可用 mysqlsqlite3)。

首次运行时,系统会询问是否安装依赖(Mix 依赖及 Node.js 依赖),输入 Y 确认。

项目目录结构速览

进入项目后你会看到:

hello_phoenix/
├── _build/          # 编译产物
├── assets/          # 前端资源(JS, CSS, 图片等)
├── config/          # 不同环境的配置文件
├── deps/            # Elixir 依赖包
├── lib/             # 应用核心代码
│   ├── hello_phoenix/   # 业务逻辑(上下文、Schema 等)
│   ├── hello_phoenix_web/ # Web 层:路由、控制器、视图、模板
│   └── hello_phoenix.ex  # 应用入口模块
├── priv/            # 静态资源、数据库迁移脚本
├── test/            # 测试文件
└── mix.exs          # 项目定义文件

核心概念映射

  • lib/<应用名>:存放业务逻辑与数据库交互(Ecto 上下文、Schema)。
  • lib/<应用名>_web:存放路由、控制器、视图、模板、通道等 Web 相关代码。
  • router.ex:定义 URL 与控制器动作的映射关系。
  • endpoint.ex:应用入口,管理请求处理管道和 WebSocket 连接。

数据库配置与创建

打开 config/dev.exs,可根据需要修改 PostgreSQL 用户名和密码:

config :hello_phoenix, HelloPhoenix.Repo,
  username: "postgres",
  password: "postgres",
  hostname: "localhost",
  database: "hello_phoenix_dev",
  stacktrace: true,
  show_sensitive_data_on_connection_error: true,
  pool_size: 10

创建并初始化数据库:

mix ecto.create        # 创建开发数据库
mix ecto.migrate       # 运行初始迁移(如果有)

mix ecto.migrate 会执行 priv/repo/migrations 下的迁移文件。

启动开发服务器

在项目根目录运行:

mix phx.server

打开浏览器访问 http://localhost:4000,看到 Phoenix 欢迎页面即表示启动成功。

现在可以开始编写你自己的页面。

路由入门

打开 lib/hello_phoenix_web/router.ex,你会看到类似定义:

scope "/", HelloPhoenixWeb do
  pipe_through :browser   # 使用浏览器管道(处理会话、csrf 等)

  get "/", PageController, :index
end

这行代码表示:

  • 访问路径 / (首页)
  • 请求类型 GET
  • 交给 HelloPhoenixWeb.PageControllerindex 函数处理

练习:添加一个新路由
scope "/" 块内增加:

get "/hello", PageController, :hello

重新加载连接,访问 http://localhost:4000/hello(目前会报错,因为控制器尚未定义动作)。

控制器与动作

创建 lib/hello_phoenix_web/controllers/page_controller.ex(若文件不存在则新建),内容如下:

defmodule HelloPhoenixWeb.PageController do
  use HelloPhoenixWeb, :controller

  def index(conn, _params) do
    render(conn, :index)  # 渲染 index 模板
  end

  def hello(conn, _params) do
    conn
    |> put_resp_content_type("text/html")
    |> send_resp(200, "<h1>Hello from Phoenix!</h1>")
  end
end

现在访问 /hello,你会看到输出字串。更常见的方式是使用模板渲染。

视图与模板

Phoenix 使用 EEx(Embedded Elixir)作为默认模板引擎。模板文件位于 lib/hello_phoenix_web/controllers/ 同级的 templates 文件夹。

对于 PageController,模板应放在
lib/hello_phoenix_web/controllers/page_html/
目录下,视图模块自动由 lib/hello_phoenix_web/controllers/page_html.ex 提供框架。若无自定义逻辑,视图文件可以极简:

defmodule HelloPhoenixWeb.PageHTML do
  use HelloPhoenixWeb, :html

  embed_templates "page_html/*"  # 嵌入该目录下所有模板
end

lib/hello_phoenix_web/controllers/page_html/ 下创建 hello.html.heex

<div class="container">
  <h1>Welcome to Phoenix!</h1>
  <p>This is the hello page.</p>
</div>

修改控制器动作使用模板:

def hello(conn, _params) do
  render(conn, :hello)   # 自动寻找对应视图下的 hello.html.heex
end

刷新 /hello,即可看到渲染后的页面。.heex 是模板的扩展名,支持内嵌 Elixir 表达式 <%= ... %>

使用 Ecto 操作数据库

Phoenix 全面集成 Ecto 进行数据持久化。所有数据库交互通过 上下文(Context) 模块组织,遵循 Phoenix 的模块化设计。

生成资源

使用代码生成器快速创建 Schema 与上下文:

mix phx.gen.html Accounts User users name:string email:string:unique age:integer

这会在 lib/hello_phoenix/accounts.ex(上下文)和相应的 Web 层文件生成 CRUD 页面。运行迁移:

mix ecto.migrate

然后将路由添加到 router.ex 中(生成器会输出提示):

scope "/", HelloPhoenixWeb do
  ...
  resources "/users", UserController
end

重启服务器后,访问 /users 即可看到用户列表,并可进行新建、编辑、删除操作。

手动查询

在 IEx 控制台(iex -S mix)或代码中,可以通过上下文模块或直接使用 Repo 操作数据:

alias HelloPhoenix.Accounts
alias HelloPhoenix.Repo

# 创建用户
Accounts.create_user(%{name: "Alice", email: "[email protected]", age: 30})

# 列出所有用户
Accounts.list_users()

# 获取单个用户
user = Accounts.get_user!(1)

Ecto 使用变更集(Changeset)进行数据验证和过滤,保证安全性。

实时功能:Channel 入门

Phoenix 的通道系统让实时通信非常简单。

定义通道路由在 lib/hello_phoenix_web/channels/user_socket.ex

channel "room:*", HelloPhoenixWeb.RoomChannel

创建通道模块 lib/hello_phoenix_web/channels/room_channel.ex

defmodule HelloPhoenixWeb.RoomChannel do
  use Phoenix.Channel

  def join("room:lobby", _message, socket) do
    {:ok, socket}
  end

  def join("room:" <> _private_room_id, _params, _socket) do
    {:error, %{reason: "unauthorized"}}
  end

  def handle_in("new_msg", %{"body" => body}, socket) do
    broadcast!(socket, "new_msg", %{body: body})
    {:noreply, socket}
  end
end

前端使用 phoenix.js 提供的 Socket 连接,即可在浏览器中实时收发消息。详细前端集成后续可参考 Phoenix 官方 Guide。

测试简介

Phoenix 内置了强大的测试支持。运行以下命令生成示例测试:

mix test

控制器测试模板(放置于 test/hello_phoenix_web/controllers/)可以这样写:

defmodule HelloPhoenixWeb.PageControllerTest do
  use HelloPhoenixWeb.ConnCase

  test "GET /", %{conn: conn} do
    conn = get(conn, "/")
    assert html_response(conn, 200) =~ "Welcome to Phoenix!"
  end
end

无需启动浏览器,即可快速验证 Web 层逻辑。

部署准备

当准备上线时,需要编译生产版本并与 Web 服务器(如 Nginx)配合:

  1. 设置环境变量 MIX_ENV=prod
  2. 执行 mix deps.get --only prodmix compile
  3. 运行 mix phx.digest 压缩并标记静态资源。
  4. 使用 mix release 构建 Erlang 发布包,可分发到无 Erlang 环境的服务器。

Phoenix 可部署到几乎任何支持 BEAM 的环境,包括云虚拟机、Heroku、Gigalixir、Fly.io 等。

下一步学习

  • 阅读 Phoenix 官方指南 深入控制器、路由和 Ecto。
  • 掌握 LiveView:用 Phoenix 直接编写富交互前端界面,几乎不用写 JavaScript。
  • 学习 Ecto 高级查询、变更集及多租户模式。
  • 探索通道与 Presence 构建聊天室、在线状态等功能。
  • 参与 Elixir 社区,浏览 Elixir ForumPhoenix GitHub

掌握 Phoenix,你就拥有了一套能优雅应对现代 Web 复杂性、同时保留函数式编程纯粹性的利器。祝你学习愉快!