Xsolla Payment CURLOPT_POSTFIELDS 返回 422 错误
支付小周
结论
这里有两个问题需要修正:
CURLOPT_POSTFIELDS不能在声明Content-Type: application/json的同时直接接收 PHP 数组。需要先用json_encode()将数组编码为 JSON。purchase.virtual_items.items必须是 JSON 数组,不能是单个 JSON 对象。因此,PHP 中需要在数组内放置商品对象:
'items' => array(
array(
'sku' => '1'
)
)
正确的数据结构
$data = array(
'user' => array(
'id' => array(
'value' => '1234567'
)
),
'settings' => array(
'project_id' => 29039
),
'purchase' => array(
'virtual_items' => array(
'items' => array(
array(
'sku' => '1'
)
)
)
)
);
编码后,items 在 JSON 中会表示为数组:
{
"purchase": {
"virtual_items": {
"items": [
{
"sku": "1"
}
]
}
}
}
下面这种写法表示对象:
"items": { "sku": "1" }
API 要求的是数组,因此应写成:
"items": [
{ "sku": "1" }
]
完整请求示例
<?php
$merchantId = 'YOUR_MERCHANT_ID';
$apiKey = 'YOUR_API_KEY';
$data = array(
'user' => array(
'id' => array(
'value' => '1234567'
)
),
'settings' => array(
'project_id' => 29039
),
'purchase' => array(
'virtual_items' => array(
'items' => array(
array(
'sku' => '1'
)
)
)
)
);
$dataJson = json_encode($data);
if ($dataJson === false) {
throw new RuntimeException(
'JSON encoding failed: ' . json_last_error_msg()
);
}
$ch = curl_init();
curl_setopt_array($ch, array(
CURLOPT_URL => sprintf(
'https://api.xsolla.com/merchant/merchants/%s/token',
rawurlencode($merchantId)
),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $dataJson,
CURLOPT_USERPWD => $merchantId . ':' . $apiKey,
CURLOPT_HTTPAUTH => CURLAUTH_BASIC,
CURLOPT_HTTPHEADER => array(
'Content-Type: application/json',
'Accept: application/json',
'Content-Length: ' . strlen($dataJson)
)
));
$result = curl_exec($ch);
if ($result === false) {
throw new RuntimeException('cURL error: ' . curl_error($ch));
}
$httpStatus = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpStatus < 200 || $httpStatus >= 300) {
throw new RuntimeException(
'Xsolla API returned HTTP ' . $httpStatus . ': ' . $result
);
}
echo $result;
错误原因
第一次请求把 PHP 数组直接传给了 CURLOPT_POSTFIELDS。这种情况下,cURL 通常会按表单数据处理数组,而不会自动生成 JSON。但请求头声明的是:
Content-Type: application/json
请求体与声明的内容类型不一致,服务端无法将其解析为 JSON,也就读不到 settings.project_id,所以返回“参数缺失”。
改用 json_encode() 后,请求体已经是有效的 JSON。不过,原有结构会生成:
"items": {
"sku": "1"
}
Xsolla 的 JSON Schema 要求 items 是数组,因此会返回:
Object value found, but an array is required
在商品对象外再包一层数字索引数组,就能生成接口要求的 [...]。
注意事项
- 声明
Content-Type: application/json后,不要将 PHP 数组直接传给CURLOPT_POSTFIELDS。 - 即使只有一个商品,
items也必须是数组。 - 添加多个商品时,可以继续向数组中追加:
'items' => array(
array('sku' => '1'),
array('sku' => '2')
)
project_id应按照接口要求保留为整数,不要无故改成字符串。- 示例中的商户 ID、API Key、项目 ID 和 SKU 都需要替换为真实值。不要把 API Key 输出到日志或错误页面。
Content-Length通常由 cURL 自动计算,不是必需项,保留或删除都可以。
备注:内容仅供参考。
