PAYATHON 2026

如何在 Pyramid 中读取 HTTP POST 参数?

支付小周

结论

对于 Content-Type: application/x-www-form-urlencoded 的 POST 请求,应通过 request.POST 读取表单参数,不要使用 request.json_body。

form_data = request.POST
payment_id = form_data.get("id")

如需普通 dict,可以直接转换:

data = dict(request.POST)

示例请求解析后的结果相当于:

{
    "id": "tr_uH4yPGBahB"
}

原因

request.json_body 会使用 JSON 解析器处理请求正文,而下面这段正文:

id=tr_uH4yPGBahB

是 URL 编码的表单数据,并非合法 JSON,因此会触发 ValueError 或相应的 JSON 解码异常。

合法的 JSON 正文应类似:

{"id": "tr_uH4yPGBahB"}

同时需要配合:

Content-Type: application/json

当前请求使用的是:

Content-Type: application/x-www-form-urlencoded

Pyramid 会按照表单编码规则解析正文,并通过 request.POST 提供解析结果。

读取单个参数

from pyramid.view import view_config


@view_config(route_name="payment_webhook", renderer="json")
def payment_webhook(request):
    payment_id = request.POST.get("id")

    if payment_id is None:
        request.response.status_code = 400
        return {"error": "Missing form field: id"}

    return {"id": payment_id}

也可以通过下标读取:

payment_id = request.POST["id"]

两种写法的区别如下:

  • request.POST.get("id") 在参数不存在时返回 None。
  • request.POST["id"] 在参数不存在时抛出 KeyError。

处理外部 webhook 时,通常更适合使用 get(),再主动校验参数是否存在。

转换为 dict

request.POST 是一个类似字典的多值映射对象,可以直接转为普通字典:

data = dict(request.POST)

转换后即可按普通字典读取:

payment_id = data.get("id")

完整示例:

@view_config(route_name="payment_webhook", renderer="json")
def payment_webhook(request):
    data = dict(request.POST)

    request.registry.settings["logger"].debug(
        "Receiving form webhook data: %r",
        data,
    )

    return {
        "received": True,
        "id": data.get("id"),
    }

实际项目中,不应在日志里记录密码、访问令牌、签名密钥或完整的支付信息。

处理同名参数

表单允许同一个字段出现多次:

tag=python&tag=pyramid

直接转换为普通 dict 时,可能只保留其中一个值。要保留所有值,应使用 getall():

tags = request.POST.getall("tag")

返回结果为:

["python", "pyramid"]

也可以将其转换为每个字段对应一个值列表的字典:

data = {
    key: request.POST.getall(key)
    for key in request.POST
}

request.POST 与 request.params 的区别

如果只需要读取 POST 表单正文,请使用:

request.POST

request.params 通常会合并查询字符串参数和表单参数。例如:

POST /webhook?id=query-value
Content-Type: application/x-www-form-urlencoded

id=form-value

此时使用 request.params,容易混淆参数来自查询字符串还是表单正文。对于 webhook 或签名验证场景,明确使用 request.POST 更合适。

这个请求可以直接这样读取:

data = dict(request.POST)
payment_id = request.POST.get("id")

备注:内容仅供参考。