手机网站支付中间页商品名称中的加号丢失
结论
加号丢失通常与 URL 编码有关。
在查询字符串或 application/x-www-form-urlencoded 请求体中,服务端会把字符 + 解析为空格。如果直接传递:
subject=300+15 W币
支付中间页收到的商品名称可能会变成:
300 15 W币
页面进一步处理空白后,看起来就像加号消失了。
应对商品名称进行正确的 URL 编码,把 + 编码为 %2B,不要手工拼接未经编码的请求参数。
原因分析
手机网站支付通常通过 URL、表单或接口参数传递商品名称。按照 application/x-www-form-urlencoded 的解析规则:
+表示空格%2B表示真正的加号- 中文和其他特殊字符也需要按 UTF-8 进行百分号编码
因此,下面的参数存在歧义:
subject=300+15 W币
正确编码后应类似:
subject=300%2B15%20W%E5%B8%81
服务端解码后,才能得到原始商品名称:
300+15 W币
参数名可能是 subject、body、goods_name 或其他名称,具体应以支付接口文档为准。
解决步骤
1. 检查提交前的原始参数
先确认业务系统中的商品名称包含加号:
300+15 W币
如果生成支付参数前加号就已经丢失,应检查数据库、模板渲染或字符串处理逻辑。
2. 统一编码参数值
使用编程语言提供的 URL 编码方法处理参数值。不要只替换中文,也不要直接拼接整段 URL。
Java 示例:
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
String subject = "300+15 W币";
String encodedSubject = URLEncoder.encode(
subject,
StandardCharsets.UTF_8
);
System.out.println(encodedSubject);
// 300%2B15+W%E5%B8%81
URLEncoder 会把空格编码为 +,把原始加号编码为 %2B。这是 application/x-www-form-urlencoded 的正常编码结果。
JavaScript 示例:
const subject = "300+15 W币";
const encodedSubject = encodeURIComponent(subject);
console.log(encodedSubject);
// 300%2B15%20W%E5%B8%81
使用 URLSearchParams 时,可以让运行环境自动完成编码:
const params = new URLSearchParams({
subject: "300+15 W币"
});
console.log(params.toString());
// subject=300%2B15+W%E5%B8%81
PHP 示例:
<?php
$subject = '300+15 W币';
$encodedSubject = urlencode($subject);
echo $encodedSubject;
// 300%2B15+W%E5%B8%81
3. 避免手工拼接请求地址
不要这样构造参数:
const url = paymentUrl + "?subject=" + subject;
可以改为:
const url = new URL(paymentUrl);
url.searchParams.set("subject", "300+15 W币");
window.location.href = url.toString();
如果通过 HTML 表单提交支付参数,可直接将原始商品名称放入隐藏字段,浏览器通常会按照表单规则进行编码:
<form method="post" action="https://example.com/payment">
<input type="hidden" name="subject" value="300+15 W币">
<button type="submit">支付</button>
</form>
通过 JavaScript 动态赋值时,应设置元素的 value 属性,不要手工生成未经转义的 HTML 字符串。
4. 核对服务端收到的值
分别记录或检查以下阶段的数据:
业务原始值:300+15 W币
发送内容:subject=300%2B15...
服务端解析值:300+15 W币
如果发送内容仍是 300+15,说明编码没有生效。如果发送内容已经包含 %2B,但支付页面仍未显示加号,则应继续检查支付服务端是否重复解码或过滤了字符。
与签名相关的注意事项
支付请求通常包含签名。修改编码方式时,要确保签名原文与实际发送的参数一致。
常见流程如下:
原始业务参数
→ 按支付接口规则生成待签名字符串
→ 计算签名
→ 对请求参数进行传输编码
→ 提交请求
不同支付接口对签名时机、参数排序和编码方式的要求可能不同,必须以对应接口文档为准。不要随意在签名前后替换 +、空格或 %2B,否则可能导致验签失败。
其他注意事项
- 不要用
replace("+", "%2B")代替完整的 URL 编码。它无法正确处理中文、空格、&、=等字符。 - 不要重复编码。
%2B再次编码后会变成%252B,服务端最终可能显示%2B,而不是+。 - 前后端应统一使用 UTF-8。
- 使用 SDK 时,应优先传入原始值
300+15 W币,由 SDK 完成请求编码,除非接口文档明确要求调用方预编码。 - 如果商品名称来自 URL 参数,读取后不要再次把解码结果当成已编码字符串处理。
- 排查时应查看实际 HTTP 请求中的查询字符串或请求体,不能只看前端变量值。
只要将原始加号编码为 %2B 再传输,并避免重复编码,支付中间页通常就能正确显示「300+15 W币」。
备注:内容仅供参考。
