PAYATHON 2026

使用 JSON 向服务器发送数据失败

支付老李

结论

在 jQuery $.ajax() 中发送 JSON 时,需要先用 JSON.stringify() 将请求体转换成 JSON 字符串,并通过大小写正确的 contentType 设置请求头:

contentType: "application/json; charset=UTF-8"

dataType: "json" 只表示希望服务器返回 JSON,不会把发送的数据转换成 JSON。如果直接将 JavaScript 对象传给 data,jQuery 默认会将其序列化为表单数据,服务器收到的内容类型可能仍然是:

application/x-www-form-urlencoded; charset=UTF-8

正确的 AJAX 配置

const payload = {
    storeId: "",
    orderId: "",
    amount: 400.00,
    currency: "980",
    partsCount: 6,
    merchantType: "PP",
    products: [
        {
            name: "TV",
            count: 2,
            price: 100.00
        },
        {
            name: "microwave",
            count: 1,
            price: 200.00
        }
    ],
    responseUrl: "https://shop.com/response",
    redirectUrl: "https://shop.com/redirect",
    signature: ""
};

$.ajax({
    url: "https://payparts2.privatbank.ua/ipp/v2/payment/create",
    method: "POST",
    contentType: "application/json; charset=UTF-8",
    dataType: "json",
    processData: false,
    data: JSON.stringify(payload),

    success: function (response) {
        console.log(response);
    },

    error: function (xhr, textStatus, errorThrown) {
        console.error("Request failed:", xhr.status);
        console.error(xhr.responseText);
        console.error(textStatus, errorThrown);
    }
});

这些配置项各有不同作用:

  • contentType 设置发送给服务器的请求体类型。
  • dataType 告诉 jQuery 服务器将返回什么格式。
  • JSON.stringify(payload) 将 JavaScript 对象转换为 JSON 文本。
  • processData: false 阻止 jQuery 将数据转换成查询字符串。

传入的内容已经是 JSON 字符串时,processData: false 通常不是必需的,但显式写出可以让请求意图更清楚。

检查配置名称和大小写

jQuery 的选项名称区分大小写,正确写法是:

contentType

下面这些写法都不会被识别为 jQuery 的 contentType 配置:

ContentType: "application/json"
contenttype: "application/json"
"Content-Type": "application/json"

也可以通过 headers 设置请求头:

headers: {
    "Accept": "application/json",
    "Content-Type": "application/json; charset=UTF-8"
}

不过,在 jQuery 中直接使用 contentType 选项即可,没有必要重复设置同一个请求头。

避免表单同时执行默认提交

如果 AJAX 请求由 <form> 的提交事件触发,还需要阻止浏览器执行普通的表单提交。否则,浏览器可能在发送 AJAX 请求后,再发送一个默认的 application/x-www-form-urlencoded 请求:

$("#payment-form").on("submit", function (event) {
    event.preventDefault();

    $.ajax({
        url: "https://payparts2.privatbank.ua/ipp/v2/payment/create",
        method: "POST",
        contentType: "application/json; charset=UTF-8",
        dataType: "json",
        data: JSON.stringify(payload)
    });
});

如果按钮不负责提交表单,也可以将其类型设为:

<button type="button" id="pay-button">Pay</button>

浏览器跨域请求可能仍然失败

该接口标明为 server-server,通常应由商城后端调用,而不是由浏览器中的 JavaScript 直接请求。

网页跨域发送 application/json 请求时,浏览器会先发送一个 OPTIONS 预检请求。只有支付服务器明确允许商城域名、POST 方法和 Content-Type 请求头,浏览器才会继续发送正式请求。客户端代码无法自行绕过 CORS。

建议采用以下调用链路:

浏览器 → 商城后端 → 支付接口

这样可以避免签名密钥和商户凭证暴露在浏览器中。后端也能校验订单金额、商品信息和支付结果,防止用户篡改请求。

浏览器只需将订单标识发送给商城后端。后端再从数据库读取可信的订单信息,生成 signature,并以 JSON 格式请求支付接口。

不要尝试在浏览器中手动设置 Accept-Encoding。它是由浏览器管理的受限请求头,而 UTF-8 也不是 HTTP 内容编码。字符集应该写在 Content-Type 中:

Content-Type: application/json; charset=UTF-8
Accept: application/json

还要核对金额

示例中的商品金额合计为:

2 × 100.00 + 1 × 200.00 = 400.00

但原请求中的 amount 是 300.00。如果支付接口要求订单总金额与商品明细合计一致,那么即使 JSON 格式正确,请求也可能因金额不符而被拒绝。最终金额和签名规则应以该支付接口当前的服务端文档为准。

备注:内容仅供参考。