elli 请求参数解析完整教程:GET/POST 参数、URI 解码与表单处理的实战清单
elli 是一个简单、健壮且高性能的 Erlang Web 服务器,专为 HTTP API 场景设计。本教程将围绕 elli 请求参数解析 这一核心主题,用最少的代码带你掌握 GET 参数、POST 参数、URI 解码与表单处理的全部技巧,并附上一份可以直接抄作业的实战清单。无论你是 Erlang 新手,还是刚接触 elli 的普通用户,读完本文都能在自己的回调函数里轻松搞定参数读取。
一、先认识 elli 的请求对象与回调入口
在 elli 中,每个 HTTP 请求都会被封装为一个 #req{} 记录,定义在 elli.hrl 中,其中与参数解析最相关的字段是:
args:URL 查询字符串解析后的参数列表(GET 参数)body:请求体二进制数据(POST 数据来源)headers:请求头列表raw_path:包含查询字符串的原始路径
而所有参数读取的便捷函数都集中在 elli_request.erl 这个模块里。你的回调函数只要实现 handle/2,就能拿到 Req 并调用这些函数,参考 elli_example_callback.erl 的写法:
handle(Req, _Args) ->
handle(Req#req.method, elli_request:path(Req), Req).
二、GET 参数解析:三种常用姿势
GET 参数来自 URL 的查询字符串,比如 /hello?name=knut。elli 在收到请求时就会自动完成解析,把结果放进 args 字段,解析逻辑见 elli_http.erl 中的 split_args/1。
姿势 1:get_arg/2、get_arg/3 读取单个参数
这是最常用的方式,第二个参数是默认值,当参数不存在时返回默认值:
Name = elli_request:get_arg(<<"name">>, Req, <<"undefined">>),
{ok, [], <<"Hello ", Name/binary>>}.
姿势 2:get_args/1 一次拿到全部参数
返回一个 proplist,便于批量处理或循环遍历:
Args = elli_request:get_args(Req),
%% 例如 [{<<"name">>, <<"knut">>}, {<<"foo">>, true}]
姿势 3:无值参数返回 true
这是 elli 的一个贴心设计:对于 ?foo 这种没有 = 的参数,解析结果为 {<<"foo">>, true},你可以据此判断某个开关参数是否被携带。对应测试见 elli_tests.erl 中的 get_args() 用例。
三、URI 解码实战:get_arg_decoded 系列
URL 中的特殊字符会被编码,例如空格变成 %20、= 变成 %3D。如果你直接用 get_arg 读取,拿到的是原始编码值,中文和特殊字符会乱码。这时就该用 URI 解码 版本的函数:
%% 请求 /decoded-hello?name=knut%3D
Name = elli_request:get_arg_decoded(<<"name">>, Req, <<"undefined">>),
%% 结果 Name = <<"knut=">>,而不是 <<"knut%3D">>
对应的批量解码函数是 get_args_decoded/1,它会遍历整个参数列表并逐一解码。底层实现调用了 Erlang 自带的 http_uri:decode/1(见 elli_request.erl 第 77-82 行)。
黄金法则:凡是参数值可能包含中文、空格或特殊符号,一律优先使用 *_decoded 系列函数,避免乱码坑。
四、POST 参数解析与表单处理:完整方案
POST 参数藏在请求体(body)中,elli 不会自动解析,需要显式调用。表单处理的核心是 body_qs/1:它先检查 Content-Type 是否为 application/x-www-form-urlencoded,然后调用 split_args/1 把 body 拆成参数列表(见 elli_request.erl 第 84-94 行)。
单个 POST 参数:post_arg/3
Name = elli_request:post_arg(<<"name">>, Req, <<"undefined">>),
解码版本:post_arg_decoded/3
%% body 为 name=foo&city=New%20York
City = elli_request:post_arg_decoded(<<"city">>, Req, <<"undefined">>),
%% 结果 City = <<"New York">>
全部 POST 参数:post_args/1 与 post_args_decoded/1
All = elli_request:post_args_decoded(Req),
⚠️ 重要提示:body_qs/1 只有在 Content-Type 正确时才工作。如果客户端忘了设置 application/x-www-form-urlencoded,它会直接抛出 badarg。因此 POST 场景下务必确保前端正确设置请求头,这也是表单处理最常见的报错原因。
五、实战清单:照抄就能用的完整示例
参考 elli_example_callback.erl 第 39-44 行的 POST 示例,下面是一份完整的参数处理回调:
%% GET 带解码:/hello?name=张三
handle('GET', [<<"hello">>], Req) ->
Name = elli_request:get_arg_decoded(<<"name">>, Req, <<"world">>),
{ok, [], <<"Hello ", Name/binary>>};
%% POST 表单:name=foo&city=New%20York
handle('POST', [<<"hello">>], Req) ->
Name = elli_request:post_arg(<<"name">>, Req, <<"undefined">>),
City = elli_request:post_arg_decoded(<<"city">>, Req, <<"undefined">>),
{ok, [], <<"Hello ", Name/binary, " of ", City/binary>>};
对应的自动化测试(elli_tests.erl 中的 post_args())验证了返回结果是 Hello foo of New York,证明整条链路完全可用。
六、进阶技巧与常见坑清单
| 场景 | 推荐函数 | 注意事项 |
|---|---|---|
| 读取单个 GET 参数 | get_arg/2,3 | 返回二进制,未命中给默认值 |
| 解码 GET 参数 | get_arg_decoded/2,3 | 中文/特殊字符必用 |
| 读取全部 GET 参数 | get_args/1 | 无值参数为 true |
| 读取单个 POST 参数 | post_arg/2,3 | 依赖正确 Content-Type |
| 解码 POST 参数 | post_arg_decoded/2,3 | 表单处理首选 |
| 读取原始查询串 | query_str/1 | 取 ? 后面的原文 |
| 读取请求头 | get_header/2,3 | 键值为二进制 |
最后提醒:elli 的参数解析 API 设计得非常克制——每个函数都有「普通版」和「解码版」两种,普通版速度快、解码版更安全。只要记住「有编码就解码」这条原则,再结合本文的实战清单,你就能在 elli 中游刃有余地处理 GET/POST 参数与表单数据了。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



