Phoenix Elixir Web 框架
什么是 Phoenix?
Phoenix 是用 Elixir 语言编写的 Web 开发框架,它基于久经考验的 Erlang VM(BEAM),天生具备高并发、低延迟与容错能力。Phoenix 借鉴了 Ruby on Rails 等框架的“约定优于配置”理念,同时保留了函数式编程的优点,让你能用简洁的代码构建实时、高性能的 Web 应用。
如果你追求流畅的开发体验,又需要支撑百万级并发连接,Phoenix 是目前最值得投入学习的技术之一。
为什么选择 Phoenix?
- 高性能与高并发:运行在 BEAM 虚拟机上,轻松处理海量 WebSocket 连接和请求。
- 实时功能内建:通过通道(Channels)和 Presence 实现实时通信,无需引入第三方库。
- 函数式、不可变数据:Elixir 的模式匹配与不可变数据让代码易于推理和测试。
- 强大的工具链:Mix 构建工具、Ecto 数据库层、LiveView 服务端渲染交互组件等开箱即用。
- 容错与分布式:基于 Erlang/OTP 的监督树机制,生产环境更健壮。
环境准备
开始之前,确保本地已安装以下工具:
- Elixir (建议 1.14 或以上)
访问 elixir-lang.org 根据操作系统进行安装。 - Erlang/OTP (通常与 Elixir 一起安装)
- PostgreSQL (Phoenix 默认数据库)
确保 PostgreSQL 服务已启动。 - 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 作为数据库(也可用mysql或sqlite3)。
首次运行时,系统会询问是否安装依赖(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.PageController的index函数处理
练习:添加一个新路由
在 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)配合:
- 设置环境变量
MIX_ENV=prod。 - 执行
mix deps.get --only prod和mix compile。 - 运行
mix phx.digest压缩并标记静态资源。 - 使用
mix release构建 Erlang 发布包,可分发到无 Erlang 环境的服务器。
Phoenix 可部署到几乎任何支持 BEAM 的环境,包括云虚拟机、Heroku、Gigalixir、Fly.io 等。
下一步学习
- 阅读 Phoenix 官方指南 深入控制器、路由和 Ecto。
- 掌握 LiveView:用 Phoenix 直接编写富交互前端界面,几乎不用写 JavaScript。
- 学习 Ecto 高级查询、变更集及多租户模式。
- 探索通道与 Presence 构建聊天室、在线状态等功能。
- 参与 Elixir 社区,浏览 Elixir Forum 和 Phoenix GitHub。
掌握 Phoenix,你就拥有了一套能优雅应对现代 Web 复杂性、同时保留函数式编程纯粹性的利器。祝你学习愉快!