POST REFUND 自 2 月 10 日起返回 400 错误
支付小周
结论
请求失败是因为请求体的序列化方式不对。当前的 payload 是对象,不是 JSON 字符串。即使手动设置了 Content-Type: application/json,客户端仍可能将对象编码成表单数据,造成请求头声明的格式与实际请求体不一致。
发送请求前,应使用 JSON.stringify() 序列化 payload,并通过客户端的 contentType 选项指定媒体类型。
解决方法
如果脚本使用 Google Apps Script 的 UrlFetchApp.fetch(),可以这样发送请求:
const url = 'https://connect.squareup.com/v1/me/refunds';
const requestBody = {
payment_id: paymentId,
type: 'FULL',
reason: 'reason'
};
const options = {
method: 'post',
headers: {
Authorization: `Bearer ${personalId}`,
Accept: 'application/json'
},
contentType: 'application/json',
payload: JSON.stringify(requestBody),
muteHttpExceptions: true
};
const response = UrlFetchApp.fetch(url, options);
Logger.log(response.getResponseCode());
Logger.log(response.getContentText());
需要把 payload 写成:
payload: JSON.stringify(requestBody)
不要直接传入对象:
payload: requestBody
原因
在 UrlFetchApp 等 HTTP 客户端中,如果 payload 是 JavaScript 对象,客户端通常会将其编码为表单数据,例如:
payment_id=...&type=FULL&reason=reason
但请求头声明的格式却是:
Content-Type: application/json
服务器会按 JSON 解析请求体,但实际收到的内容并不是合法 JSON,因此可能返回:
{
"type": "bad_request",
"message": "The Content-Type of this request is not supported. Supported type(s): application/json"
}
配置对象中出现了正确的 Content-Type,不代表实际传输的请求体就是 JSON。请求头声明的类型必须与请求体格式一致。
如果使用其他 HTTP 客户端
处理方式相同,先把对象序列化为 JSON,再发送请求。例如使用 fetch:
const response = await fetch(url, {
method: 'POST',
headers: {
Authorization: `Bearer ${personalId}`,
Accept: 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
payment_id: paymentId,
type: 'FULL',
reason: 'reason'
})
});
使用 curl 排查时,可以发送一条等价请求:
curl -X POST 'https://connect.squareup.com/v1/me/refunds' \
-H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
--data '{"payment_id":"PAYMENT_ID","type":"FULL","reason":"reason"}'
注意事项
- 不要在日志中记录完整的访问令牌、付款 ID 或客户信息。
- JSON 字符串必须使用双引号,也不能包含示例之外的反引号、引号或右花括号。
Content-Type错误不一定表示请求头缺失,也可能是请求体格式与声明的类型不一致。- 单凭这条错误信息,无法确认服务器是否在 2 月 10 日调整过校验策略。即使服务端以前允许这种格式不一致的请求,也应按照 API 要求发送真正的 JSON。
- 如果序列化后仍然报错,请记录实际的 HTTP 状态码和响应体,并检查当前调用的 Square API 端点、认证方式和请求字段是否仍适用于该接口。
备注:内容仅供参考。
