CURL 是 PHP 中進行 HTTP 請求的利器,但在使用 CURLOPT_POSTFIELDS 參數時,若不注意細節,可能會導致請求失敗或伺服器返回 500 錯誤。本文深入探討該參數的行為差異,並提供最佳實踐建議。
一般開發者習慣直接將陣列傳給 CURLOPT_POSTFIELDS:
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
然而,當 $post_data 為陣列時,CURL 會自動將 Content-Type 標頭設為 multipart/form-data,並包含 boundary 分隔符。這本意是為了支援檔案上傳(如 @/path/to/file 語法),但若僅提交普通表單資料,這會導致請求體變大,且部分伺服器無法正確解析,回傳 500 錯誤。
對比之下,若先用 http_build_query() 將陣列轉為 URL 編碼字串:
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post_data));
則 Content-Type 會是標準的 application/x-www-form-urlencoded,這與瀏覽器原生 <form> 提交一致,相容性最佳,封包也更小。
The full data to post in a HTTP "POST" operation. To post a file, prepend a filename with @ and use the full path. This can either be passed as a urlencoded string like 'para1=val1¶2=val2&...' or as an array with the field name as key and field data as value. If value is an array, the Content-Type header will be set to multipart/form-data.
文件明確指出:傳入陣列時會強制使用 multipart/form-data。這雖然為了兼容檔案上傳,但對於純資料提交卻是多餘且可能有害的。
http_build_query($post_data) 將陣列轉為字串再傳入。CURLFile 類(PHP 5.5+)或 @ 前綴(舊版)處理檔案欄位。CURLOPT_HTTPHEADER => ['Content-Type: application/x-www-form-urlencoded'],但仍建議轉字串更穩妥。理解 CURLOPT_POSTFIELDS 的預設行為,避免不必要的 multipart/form-data,能顯著提升 API 請求的穩定性與效能。記住:純資料提交,請先 http_build_query()。