呼叫 RESTful API 時常需以 JSON 格式 POST 資料。關鍵在於設定正確的 Content-Type: application/json 標頭,並將 PHP 陣列 json_encode 後送出。本文提供三種封裝層級的範例:直接呼叫、可重用函式、實際業務 JSON 結構(微信選單建立)。
$data = ['name' => 'Hagrid', 'age' => 36];
$json = json_encode($data);
$ch = curl_init('https://api.example.com/users');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_POSTFIELDS => $json,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'Content-Length: ' . strlen($json),
],
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
必設 Header:Content-Type: application/json 告知伺服器請求體格式;Content-Length 雖非強制但建議加上,避免某些代理/伺服器拒絕 chunked 請求。
<?php
$data = ['name' => 'Hagrid', 'age' => '36'];
$json = json_encode($data);
$ch = curl_init('https://api.local/rest/users');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_POSTFIELDS, $json);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'Content-Length: ' . strlen($json),
]);
$result = curl_exec($ch);
if ($result === false) {
throw new Exception('cURL Error: ' . curl_error($ch));
}
curl_close($ch);
var_dump(json_decode($result, true));
function httpPostJson(string $url, array $data, array $extraHeaders = []): array {
$json = json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $json,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => array_merge([
'Content-Type: application/json; charset=utf-8',
'Content-Length: ' . strlen($json),
], $extraHeaders),
CURLOPT_TIMEOUT => 10,
CURLOPT_CONNECTTIMEOUT => 5,
CURLOPT_SSL_VERIFYPEER => true, // 生產環境保持 true
]);
$response = curl_exec($ch);
$errno = curl_errno($ch);
$error = curl_error($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
return [
'http_code' => $httpCode,
'body' => $response,
'error_no' => $errno,
'error_msg' => $error,
'decoded' => $errno === 0 ? json_decode($response, true) : null,
];
}
// 使用
$res = httpPostJson('https://api.example.com/orders', ['item_id' => 123, 'qty' => 2]);
if ($res['http_code'] === 200) {
// 成功
}
$menuJson = '{
"button": [
{"type":"click","name":"今日歌曲","key":"V1001_TODAY_MUSIC"},
{"type":"click","name":"歌手簡介","key":"V1001_TODAY_SINGER"},
{"name":"菜單","sub_button":[
{"type":"click","name":"hello world","key":"V1001_HELLO_WORLD"},
{"type":"click","name":"贊一下我們","key":"V1001_GOOD"}
]}
]
}';
$url = 'https://api.weixin.qq.com/cgi-bin/menu/create?access_token=' . $accessToken;
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_POSTFIELDS => $menuJson,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'Content-Length: ' . strlen($menuJson),
],
]);
$response = curl_exec($ch);
// 成功回傳:{"errcode":0,"errmsg":"ok"}
curl_close($ch);
| 問題 | 原因 | 解決 |
|---|---|---|
| 伺服器回傳 400/415 | 缺少或錯誤 Content-Type | 務必設定 application/json |
| 中文變亂碼 | json_encode 預設轉義 Unicode | 加旗標 JSON_UNESCAPED_UNICODE |
| 大數據截斷 | 預設 POST 大小限制 | 檢查 post_max_size、Nginx client_max_body_size |
| SSL 驗證失敗 | 憑證不信任 | 正確部署 CA 憑證,勿盲目關閉 CURLOPT_SSL_VERIFYPEER |
| 超時無回應 | 未設定 timeout | 務必設 CURLOPT_TIMEOUT、CURLOPT_CONNECTTIMEOUT |