PHP cURL以multipart/form-data调用Bullhorn API解析简历无数据问题
这种情况我太熟悉了——Postman测一切正常,自己写的PHP cURL就哑火,请求能发出去但拿不到解析数据,大概率是请求构造的细节和Postman没对齐。我帮你梳理几个最可能的排查方向和解决方案:
1. 别手动设置multipart/form-data的Content-Type
很多人会犯这个错:手动给cURL加Content-Type: multipart/form-data头,但没指定正确的边界字符串。其实PHP的cURL在你传入数组形式的POSTFIELDS(尤其是包含CURLFile时),会自动生成正确的边界并设置Content-Type头。如果手动指定,反而会和实际发送的边界不匹配,导致服务器无法解析表单数据。
✅ 正确做法:删掉手动设置的Content-Type头,让cURL自动处理。
2. 确保表单字段名和Postman完全一致
Bullhorn的简历解析API对表单字段名有严格要求,比如可能要求字段名为file或者resume。你去Postman里看一下你测试时用的字段名(在Body的form-data里),PHP代码里的字段名必须和它完全一样,不能有拼写错误、大小写差异。
比如Postman里用的是file,那PHP里要这么写:
$postData = [ 'file' => new CURLFile($yourFilePath) ];
3. 用CURLFile替代旧的@语法
PHP 5.5之后就推荐用CURLFile来处理文件上传,旧的@/path/to/file语法在高版本PHP里会被CURLOPT_SAFE_UPLOAD默认禁用,导致文件无法正确上传。
另外要注意:
- 最好用绝对路径指定文件,避免相对路径找不到文件的问题
- 可以指定MIME类型和文件名,和Postman里的设置对齐:
$fileMime = mime_content_type($filePath); $fileName = basename($filePath); 'file' => new CURLFile($filePath, $fileMime, $fileName)
4. 检查请求头是否和Postman完全匹配
Postman里的请求头(比如Authorization、Accept)都要在PHP里原样复制过来:
- 确认Bearer token是否正确设置,没有过期
- 加上
Accept: application/json头,确保服务器返回JSON格式的响应,而不是其他格式
示例请求头设置:
$headers = [ 'Authorization: Bearer ' . $yourAccessToken, 'Accept: application/json' ]; curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
5. 开启cURL调试,对比Postman的请求
如果上面都排查了还是不行,就开启cURL的 verbose 模式,看看实际发送的请求和Postman的Raw请求有什么差异:
// 开启调试日志 $verboseLog = fopen('php://temp', 'w+'); curl_setopt($ch, CURLOPT_VERBOSE, true); curl_setopt($ch, CURLOPT_STDERR, $verboseLog); // 执行请求后输出日志 rewind($verboseLog); echo "请求日志:\n" . stream_get_contents($verboseLog) . "\n";
把这个日志和Postman里的「Raw」请求(在Postman的请求详情里找)对比,重点看:
- Content-Type的边界是否一致
- 表单字段的名称、文件的MIME类型是否匹配
- 所有请求头是否完全一致
完整的示例代码
这里给你一个经过验证的完整代码模板,你可以替换成自己的参数测试:
<?php // 配置参数 $bullhornToken = 'your_bullhorn_access_token'; $resumePath = '/absolute/path/to/your/resume.pdf'; // 用绝对路径! $apiEndpoint = 'https://rest.bullhornstaffing.com/rest-services/your-tenant/resume/parse'; // 初始化cURL $ch = curl_init($apiEndpoint); // 设置POST请求 curl_setopt($ch, CURLOPT_POST, true); // 构造表单数据 $postFields = [ 'file' => new CURLFile( $resumePath, mime_content_type($resumePath), basename($resumePath) ) ]; curl_setopt($ch, CURLOPT_POSTFIELDS, $postFields); // 设置请求头 $headers = [ "Authorization: Bearer {$bullhornToken}", "Accept: application/json" ]; curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); // 接收响应 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // 执行请求 $response = curl_exec($ch); // 处理错误 if (curl_errno($ch)) { die("CURL错误: " . curl_error($ch)); } // 解析并输出响应 $parsedResponse = json_decode($response, true); print_r($parsedResponse); curl_close($ch);
按照上面的步骤排查,基本就能定位到问题了——大概率是某个细节和Postman没对齐,毕竟Bullhorn的API对请求格式要求还是比较严格的。
内容的提问来源于stack exchange,提问作者Josh Kautz

