使用 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 格式正确,请求也可能因金额不符而被拒绝。最终金额和签名规则应以该支付接口当前的服务端文档为准。
备注:内容仅供参考。
