向 payment gateway 传值时出现 media type unsupported
支付阿杰
结论
HTTP 415 Unsupported Media Type 表示请求的 Content-Type 与支付网关支持的媒体类型不匹配,通常与字段是否成功填充无关。
如果支付网关要求普通表单提交,应使用 POST,浏览器发送的内容类型应为:
Content-Type: application/x-www-form-urlencoded
除非网关文档明确要求上传文件,否则不要将表单设置为 multipart/form-data。同时,所有 <input> 都必须放在完整的 <form> 标签内。
正确的表单结构
OpenCart 模板可以这样写:
<form action="<?php echo htmlspecialchars($action, ENT_QUOTES, 'UTF-8'); ?>"
method="post">
<input type="hidden" name="merchant_id"
value="<?php echo htmlspecialchars($merchant_id, ENT_QUOTES, 'UTF-8'); ?>" />
<input type="hidden" name="order_id"
value="<?php echo htmlspecialchars($order_id, ENT_QUOTES, 'UTF-8'); ?>" />
<input type="hidden" name="amount"
value="<?php echo htmlspecialchars($amount, ENT_QUOTES, 'UTF-8'); ?>" />
<input type="hidden" name="currency"
value="<?php echo htmlspecialchars($currency, ENT_QUOTES, 'UTF-8'); ?>" />
<input type="hidden" name="return_url"
value="<?php echo htmlspecialchars($return_url, ENT_QUOTES, 'UTF-8'); ?>" />
<input type="submit" value="Pay" class="button" />
</form>
普通 HTML 表单不设置 enctype 时,浏览器默认使用:
application/x-www-form-urlencoded
也可以显式声明:
<form action="https://gateway.example/payment"
method="post"
enctype="application/x-www-form-urlencoded">
常见错误
如果当前代码是下面这种形式:
<form action="https://gateway.example/payment"
method="post"
enctype="multipart/form-data">
浏览器会发送:
Content-Type: multipart/form-data; boundary=...
不少支付接口只接受 URL 编码表单或 JSON,收到这种请求后会直接返回 415 Unsupported Media Type。通常只需删除 enctype:
<form action="https://gateway.example/payment" method="post">
还要检查这些内容:
<form>的action是否正确,method是否为"post"。- 每个字段是否都有网关规定的
name。服务器接收的是name,不是id。 - 所有字段是否确实位于
<form>...</form>内。 - 是否误用了
multipart/form-data、text/plain或其他网关不支持的编码方式。 - 网关需要的是浏览器表单提交还是后端 API 请求。两种方式不能只靠修改隐藏字段来互换。
- 金额、币种、签名和回调地址的字段名与格式是否完全符合网关文档。
如果网关要求 JSON
原生表单提交不会自动生成 JSON。如果接口明确要求:
Content-Type: application/json
应由 OpenCart 后端向网关发起请求,不要直接提交 HTML 表单。例如:
$payload = [
'merchant_id' => $merchant_id,
'order_id' => $order_id,
'amount' => $amount,
'currency' => $currency,
];
$ch = curl_init($gatewayUrl);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'Accept: application/json',
],
CURLOPT_POSTFIELDS => json_encode($payload),
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
究竟应该使用 application/x-www-form-urlencoded、multipart/form-data 还是 application/json,要以支付网关的接口文档为准。变量有值并不代表可以排除 415。应打开浏览器开发者工具,在 Network 面板中查看实际请求的 Request Headers 和 Content-Type。
备注:内容仅供参考。
