PAYATHON 2026

手机网站支付中间页商品名称中的加号丢失

支付小周

结论

加号丢失通常与 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币」。

备注:内容仅供参考。