Laravel中PHP Curl与Guzzle调用OCR服务大文件上传异常问题
问题原因及解决方案
核心原因
- Expect头不兼容:Curl/Guzzle默认在请求体大小超过1KB时自动发送
Expect: 100-continue请求头,等待服务端返回100响应后才会发送实际请求体,很多老旧私有WS服务未兼容该逻辑,直接忽略该请求导致请求超时/失败,小文件因为请求体小于1KB不会触发该逻辑所以正常。 - 分块传输不兼容:大文件传输时Curl/Guzzle默认会使用
Transfer-Encoding: chunked分块传输编码,不需要提前计算Content-Length,而很多传统WS服务仅支持带Content-Length的普通POST请求,无法解析分块传输的内容导致解析失败。 - 图片字段缺少必要元信息:你当前的Guzzle/Curl代码上传图片时仅传递了文件内容,没有指定文件名、MIME类型等元信息,Postman上传时会自动补全这些参数,服务端解析表单时小文件容错率高可正常读取,大文件会因为缺少元信息解析出错。
- 超时配置不足:大文件上传+OCR识别耗时远高于小文件,你的代码中未配置Curl/Guzzle的超时参数,默认超时时间短导致请求在处理完成前就被断开。
对应修复代码
Guzzle版本
$url='http://10.0.20.113:8080/'; $req = new Client([ 'verify' => 0, 'timeout' => 120, // 可根据实际OCR处理时长调整超时时间 'expect' => false, // 禁用Expect:100-continue头 ]); $response = $req->post( $url, [ 'headers' => [ 'accept-encoding' => 'gzip, deflate, br', 'accept' => '*/*' ], 'multipart' => [ [ 'name' => 'user', 'contents' => 'admin' ], [ 'name' => 'pwd', 'contents' => 'admin' ], [ 'name' => 'doctype', 'contents' => '0' ], [ 'name' => 'new', 'contents' => '1' ], [ 'name' => 'pressmode', 'contents' => '2' ], [ 'name' => 'image1', 'contents' => $img1, 'filename' => 'image1.jpg', // 补全文件名 'headers' => ['Content-Type' => 'image/jpeg'] // 补全图片MIME类型 ], [ 'name' => 'image2', 'contents' => $img2, 'filename' => 'image2.jpg', // 补全文件名 'headers' => ['Content-Type' => 'image/jpeg'] // 补全图片MIME类型 ] ], ] ); Log::info('Response received'); return $response->getBody()->getContents();
Curl版本
$ch = curl_init(); $headers = array(); // 图片使用CURLFile对象传递,自动补全表单元信息 // 如果是内存中的图片内容,可先写入临时文件再传入CURLFile $post = array( 'user' => 'admin', 'pwd' => 'admin', 'doctype' => 0, 'new' => 1, 'pressmode' => 2, 'image1' => new CURLFile('本地图片1路径', 'image/jpeg', 'image1.jpg'), 'image2' => new CURLFile('本地图片2路径', 'image/jpeg', 'image2.jpg') ); curl_setopt_array( $ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => $headers, CURLOPT_URL => $url, CURLOPT_POSTFIELDS => $post, CURLOPT_SSL_VERIFYPEER => 0, CURLOPT_TIMEOUT => 120, // 可根据实际OCR处理时长调整超时时间 CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, CURLOPT_EXPECT_100_TIMEOUT_MS => 0, // 禁用Expect:100-continue逻辑 ] ); $result = curl_exec($ch); $response = curl_getinfo($ch);
内容的提问来源于stack exchange,提问作者Miquel Àngel
相关产品推荐
相关产品推荐

