Bandit:纯 Elixir 的 HTTP 服务器,Phoenix 默认选择,性能与正确性并重
Bandit 是一个用于 Plug & WebSock 应用程序的纯 Elixir HTTP 服务器。
秒懂
- 它是什么?
- Bandit 是一个纯 Elixir 编写的 HTTP 服务器,面向 Plug 和 WebSock 应用,自 Phoenix 1.7.11 起成为默认服务器。本文基于官方文档和仓库信息,分析其架构、配置、性能测试结果以及适用边界。
- 适合谁用?
- Bandit 适合已经使用 Phoenix 1.7 以上或纯 Plug 应用,并且希望获得比 Cowboy 更高吞吐量和更清晰代码结构的团队。它不适合那些依赖 Cowboy 特有扩展或需要深度自定义 HTTP 层行为的项目,因为 Bandit 的设计哲学是尽量将策略交给 Plug 和 WebSock,自身只保留协议正确性所需的最小逻辑。
- 能商用吗?
- 可以。MIT 是宽松许可证:你可以使用、修改并销售基于它的软件,只需保留版权和许可证声明。
- 还在维护吗?
- 在维护。仓库最近一次提交在 8 天前。
- 用什么语言写的?
- 主要是 Elixir(依据 GitHub 的语言统计)。
以上回答依据项目的 GitHub 数据(最近同步于 2026年9月14日)和我们的分析,不构成法律意见。
开源项目深度解析
为什么需要另一个 Elixir HTTP 服务器
在 Bandit 出现之前,Cowboy 是 Elixir 社区事实上的 HTTP 服务器,几乎所有 Phoenix 应用都跑在它上面。但 Cowboy 是用 Erlang 写的,它的内部逻辑对 Elixir 开发者来说是一个黑盒。Bandit 的目标是提供一个完全用 Elixir 实现的替代品,让基础设施代码可以被阅读和理解。它解决的问题很具体:当你的应用需要高性能、严格的协议合规性,同时又希望服务器代码本身是可审计的,Cowboy 的闭源性(相对于 Elixir 社区)就成了一个痛点。Bandit 直接面向 Phoenix 和 Plug 应用,它不试图成为通用服务器,而是深度绑定这些框架的抽象。
架构:Thousand Island 之上的协议层
Bandit 并非从零实现网络栈,它构建在 Thousand Island 之上,后者负责底层的 TCP 连接管理、SSL 处理和连接池。Bandit 本身专注于 HTTP 协议解析、请求路由到 Plug 管道,以及 WebSocket 帧的处理。这种分层让 Bandit 的代码量相对精简,也使得协议逻辑与网络细节分离。文档明确提到,Bandit 的目标是“最小化内部策略和 HTTP 级配置”,这意味着它尽量不解释请求,只做安全连接管理所必需的工作。对于开发者来说,这意味着你不需要学习一套新的配置语法,而是直接使用 Plug 的标准接口。
性能声明:比 Cowboy 快多少?
README 中给出了两个性能对比:在自动化的基准测试中,Bandit 的 HTTP/1.x 引擎比 Cowboy 快最多 4 倍,HTTP/2 则快最多 1.5 倍。这些数字来自项目自己的 CI 工作流,不是第三方独立测试,所以需要谨慎看待。但值得注意的是,Bandit 是专门为 Plug 应用设计的,它不需要像 Cowboy 那样做通用适配,这可能是性能提升的来源。另一个值得注意的细节是,文档声称内存使用“与 Cowboy 相当或更好”,但没有给出具体数据。如果你关心性能,应该在自己的硬件上重新跑一遍基准,而不是直接相信这个 4 倍的数字。
正确性:h2spec 和 Autobahn 的满分
Bandit 的另一个卖点是协议测试的完整性。它的 HTTP/2 实现通过了 h2spec 严格模式的全部测试,WebSocket 实现通过了 Autobahn 测试套件。这两个测试套件是业界公认的协议合规性检验工具,满分意味着 Bandit 在协议层面对 RFC 的遵循程度很高。对于生产环境来说,这比性能数字更重要,因为协议偏差会导致客户端兼容性问题。文档还提到,CI 中包含了单元测试、Credo 静态分析和 Dialyzer 类型检查,这些构成了一个相对完整的质量保障体系。但要注意,通过这些测试并不意味着没有 bug,只是说明在标准场景下行为正确。
快速上手:Phoenix 和 Plug 的配置
使用 Bandit 替换 Cowboy 非常简单。在 Phoenix 项目中,只需在 mix.exs 添加依赖 {:bandit, "~> 1.8"},然后在 config/config.exs 的 endpoint 配置中加一行 adapter: Bandit.PhoenixAdapter。文档说“就这样”,但后面也提醒,如果你设置了不常见的 endpoint 选项,可能需要调整。对于纯 Plug 应用,更直接:在 Application.start/2 的 children 列表中加入 {Bandit, plug: MyApp.MyPlug},或者用 Bandit.start_link(plug: MyPlug) 启动,默认端口是 4000。这种简洁性正是 Bandit 的设计目标,它不引入额外的配置层,所有选项都通过 t:Bandit.options/0 类型定义。
HTTPS 配置:一个常见的坑
文档特别指出,设置 HTTPS 时最常见的错误是证书和密钥的配置。Bandit 提供了一个示例,但 README 被截断了,我们看不到完整的代码。从上下文推断,你需要通过 scheme: :https 选项,并指定 keyfile 和 certfile 的路径。与 Cowboy 相比,Bandit 的配置方式可能更直接,因为它将证书加载逻辑内置在 Thousand Island 中。不过,如果你之前使用 Cowboy 的某些高级 TLS 选项,比如自定义密码套件或客户端证书验证,可能需要查阅 Bandit 的文档来确认是否支持。这里有一个真实的限制:文档没有详细列出所有 HTTPS 选项,所以对于复杂场景,你需要查阅 hexdocs 上的完整类型定义。
维护成本与许可证
Bandit 采用 MIT 许可证,这意味着你可以自由使用、修改和分发,没有 Copyleft 义务。项目目前处于活跃维护状态,默认分支是 main,但最近没有发布新版本,这可能意味着稳定期。维护成本方面,由于 Bandit 是纯 Elixir 实现,对于熟悉 Elixir 的团队来说,调试和修改内部逻辑比 Erlang 代码更容易。但这也意味着你需要依赖 Thousand Island 的更新,如果底层网络库有变化,Bandit 需要同步适配。从项目状态看,Bandit 已经实现了完整的 HTTP/1.x 和 HTTP/2 支持,以及 WebSocket 压缩,功能上不太可能有大变化,所以升级风险相对可控。
编辑结论
Bandit 适合已经使用 Phoenix 1.7 以上或纯 Plug 应用,并且希望获得比 Cowboy 更高吞吐量和更清晰代码结构的团队。它不适合那些依赖 Cowboy 特有扩展或需要深度自定义 HTTP 层行为的项目,因为 Bandit 的设计哲学是尽量将策略交给 Plug 和 WebSock,自身只保留协议正确性所需的最小逻辑。在采用前,你应该先检查现有 endpoint 配置中是否有非标准选项,特别是与 HTTPS 证书加载、压缩方式相关的设置,并运行一次完整的集成测试,确保 WebSocket 或 LiveView 功能正常。若你的应用仍停留在 Phoenix 1.6 或更早版本,WebSocket 支持需要升级到 1.7 以上,这是明确的硬性前提。
社区笔记