Laravel8使用Guzzle调用Mirakl API上传form-param文件报400错误
现有代码核心错误
- 文件上传字段传值错误:Guzzle
multipart格式上传文件时,contents参数需要传入文件流资源,当前代码传入本地磁盘路径字符串,相当于仅上传了路径文本,服务端无法接收到真实文件内容。 order_documents参数格式错误:Mirakl 接口接收multipart/form-data格式的表单数组参数,不需要手动将参数序列化为JSON字符串,当前写法会导致服务端无法解析结构化的文档元数据。- 请求头冲突风险:如果配置的请求头中手动指定了
Content-Type(尤其是固定值的multipart/form-data或application/json),会覆盖Guzzle自动生成的带正确boundary标识的Content-Type头,导致服务端无法解析表单内容。 - 无错误捕获逻辑:接口返回400时无法直接拿到服务端返回的具体错误提示,排查效率低。
修正后可运行代码
调整逻辑:直接按表单数组规则构造order_documents参数,上传时传入真实文件流,移除手动配置的冲突请求头,增加异常捕获方便定位问题。
public function upload_order(Request $request) { $order_id = $request->order_id; $filePath = ''; $fileName = ''; if ($uploadedFile = $request->file('files')) { $fileName = $uploadedFile->getClientOriginalName(); Storage::disk('invoice')->put($fileName, file_get_contents($uploadedFile->getRealPath())); $filePath = Storage::disk('invoice')->path($fileName); } $multipartData = []; // 按表单数组格式构造文档元数据,不做JSON序列化 $multipartData[] = [ 'name' => 'order_documents[0][file_name]', 'contents' => $fileName ]; $multipartData[] = [ 'name' => 'order_documents[0][type_code]', 'contents' => $request->type_code ]; // 传入打开的文件流资源,而非路径字符串 $multipartData[] = [ 'name' => 'files', 'contents' => fopen($filePath, 'r'), 'filename' => $fileName ]; $configApi = $this->configApi($this->getMarketplaceID($request->marketplace), auth()->user()->id); $url = $configApi['url'].'/api/orders/'.$order_id.'/documents'; // 移除手动配置的Content-Type头,交由Guzzle自动生成带合法boundary的头 $headers = $configApi['headers']; unset($headers['Content-Type'], $headers['content-type']); $client = new Client(['verify' => false]); try { $response = $client->request( 'POST', $url, [ 'multipart' => $multipartData, 'headers' => $headers ] ); return json_decode($response->getBody(), true); } catch (\GuzzleHttp\Exception\ClientException $e) { // 触发4xx错误时直接输出接口返回的具体错误信息,快速定位问题 dd($e->getResponse()->getBody()->getContents()); } }
- 多文件上传场景只需按索引对齐参数即可,第二个文件对应
order_documents[1][file_name]、order_documents[1][type_code],文件字段命名为files[1],依次类推。 - 如果使用Laravel自带HTTP客户端,逻辑完全一致:文件传文件实例/流资源,元数据按数组格式传递,不手动设置Content-Type头即可。
内容的提问来源于stack exchange,提问作者Tanvir Hasan
相关产品推荐
相关产品推荐

