You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP cURL单次POST请求数据重复存入数据库问题排查

问题描述

我通过PHP cURL调用自定义网站API执行单次POST请求提交数据,流程看似正常,但数据库中却重复存入了相同的数据。我尝试开启/关闭RETURNTRANSFER、FOLLOWLOCATION、VERBOSE参数,也试过ob_start、ob_get_contents、ob_end_clean方法,但重复存储的问题始终存在。

我的PHP cURL代码
$curl = curl_init();

curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
curl_setopt($curl, CURLOPT_USERPWD, $username . ':' . $pw);
curl_setopt($curl, CURLOPT_HEADER, 1);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($curl, CURLOPT_MAXREDIRS, 10);
curl_setopt($curl, CURLOPT_TIMEOUT, 30);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($curl, CURLOPT_VERBOSE, 0);
curl_setopt($curl, CURLOPT_HTTPHEADER, ['Content-type: multipart/form-data']);
curl_setopt($curl, CURLOPT_HTTPHEADER, ['Expect:']);
curl_setopt($curl, CURLOPT_HTTPHEADER, ['Accept: application/json']);

$adat = [];

$adat['data[sortOrder]'] = 1;
$adat['data[status]'] = 1;
$adat['data[productsStatus]'] = 1;
$adat['data[groupCode]'] = NULL;
$adat['data[parentCategory][id]'] = '';
$adat['data[centralCategory][id]'] = '';
$adat['data[categoryDescriptions][0][name]'] = 'Test cat 1';
$adat['data[categoryDescriptions][0][description]'] = 'Test cat 1 desc';
$adat['data[categoryDescriptions][0][language][id]'] = 'bGFuZ3VhZ2UtbGFuZ3VhZ2VfaWQ9MQ==';


curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $adat);

//ob_start();
$response = curl_exec($curl);
//$response = ob_get_contents();
//ob_end_clean();

if ($response === false) {
     echo curl_error($curl);
}

$header_size = curl_getinfo($curl, CURLINFO_HEADER_SIZE);
$httpReturnCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
$contentType = curl_getinfo($curl, CURLINFO_CONTENT_TYPE);
$lastURL = curl_getinfo($curl, CURLINFO_EFFECTIVE_URL);
$data = substr($response, curl_getinfo($curl, CURLINFO_HEADER_SIZE));
                
curl_close($curl);
                      
echo '<pre>';
print_r(json_decode($data));
echo '</pre>';
cURL请求日志
*   Trying x.x.x.x:80...
* Connected to api.url.example.address (x.x.x.x) port 80 (#0)
* Server auth using Basic with user 'username'
> POST /categoryExtend HTTP/1.1
Host: api.url.example.address
Authorization: Basic 
Accept: application/json
Content-Length: 1144
Content-Type: multipart/form-data; boundary=------------------------b05e0dbf7a681e1e

* We are completely uploaded and fine
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Server: openresty/1.13.6.1
< Date: Sat, 08 Apr 2023 18:36:36 GMT
< Content-Type: application/json
< Content-Length: 1205
< Connection: keep-alive
< Cache-Control: max-age=0, public
< Content-Security-Policy-Report-Only: frame-ancestors 'self'; report-uri /csp_logger
< Expires: Sat, 08 Apr 2023 18:36:36 GMT
< Vary: Accept-Encoding
< X-Content-Security-Policy-Report-Only: frame-ancestors 'self'; report-uri /csp_logger
< X-UA-Compatible: IE=Edge
< X-WebKit-CSP-Report-Only: frame-ancestors 'self'; report-uri /csp_logger
< X-LB: api
< X-LB: api
< 
* Connection #0 to host api.url.example.address left intact
问题排查与解决方案

从日志和代码来看,cURL仅发起了一次请求,但数据库重复存储,可从以下方向排查修复:

  1. 修复HTTP头覆盖问题
    你多次调用curl_setopt($curl, CURLOPT_HTTPHEADER, [...]),会覆盖之前的头信息,最终仅Accept: application/json生效,Content-type: multipart/form-data被丢弃。虽然cURL会自动生成该头,但手动设置被覆盖可能导致服务端解析异常,触发重复处理。
    修复方式:将所有HTTP头放入一个数组一次性设置:

    curl_setopt($curl, CURLOPT_HTTPHEADER, [
        'Content-type: multipart/form-data',
        'Expect:',
        'Accept: application/json'
    ]);
    
  2. 服务端防重复处理
    日志显示返回200 OK,但服务端可能因负载均衡(日志出现两次X-LB: api)、网络延迟导致请求被重复转发处理。

    • 给请求添加唯一标识:在POST数据中加入request_id字段(用UUID生成),服务端校验该ID,避免重复处理相同请求。
    • 检查服务端请求日志,确认是否收到多次相同请求。
  3. 限制cURL隐式重试
    部分场景下cURL可能因连接不稳定触发隐式重试,可添加参数限制:

    curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 10); // 限制连接超时时间
    curl_setopt($curl, CURLOPT_NOSIGNAL, true); // 避免信号干扰导致的重试
    
  4. 脚本防重复执行
    检查PHP脚本是否被意外重复调用(如浏览器刷新、CRON任务重复触发、前端重复提交),可添加文件锁机制:

    $lockFile = fopen('/tmp/category_post.lock', 'w');
    if (!flock($lockFile, LOCK_EX | LOCK_NB)) {
        exit('请求正在处理中');
    }
    // 执行cURL请求的代码
    flock($lockFile, LOCK_UN);
    fclose($lockFile);
    

内容的提问来源于stack exchange,提问作者Jani88

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 17:47:13