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

PHP Curl实现Google Drive多部分上传遇badContent错误求助

Google Drive Multipart上传报错:Unsupported content with type: application/octet-stream

能完成两步式媒体上传,但尝试实现Google Drive的multipart上传(不想手动处理边界逻辑)时,始终返回badContent错误,错误信息如下:

[message] => Unsupported content with type: application/octet-stream

推测问题可能是MIME类型错误,或是POST请求中未识别到文件,求解决。

现有代码

public function uploadFileToGoogleDriveMulti($accessToken, $filePath, $fileType, $fileName, $folderID)
{
    /*
    trigger_error("DEBUG: ".print_r($accessToken, true));
    trigger_error("DEBUG: ".print_r($filePath, true));
    trigger_error("DEBUG: ".print_r($fileType, true));
    trigger_error("DEBUG: ".print_r($fileName, true));
    trigger_error("DEBUG: ".print_r($folderID, true));
    */

    $cFile = curl_file_create($filePath, $fileType, $fileName);  
    //trigger_error("DEBUG: ".print_r($cFile, true));        

    $curl = curl_init();
   
    $postdata = array
    (
      'metadata' => json_encode
      (array
        (
          'name' => $fileName,
          //'parents' => array($folderID),
          //'Content-Type' => 'application/json; charset=UTF-8' 
        )
      ),
      //'file' => new CURLFILE($filePath, $fileType),
      //'file_contents'=>$cFile
      'file' => $cFile,
      //'Content-Type' => $fileType . '\n\n' . file_get_contents($filePath)                   
    );
            
    $headers = array
    (
      'Authorization: Bearer ' . $accessToken,
      //'Content-Type: multipart/form-data',
      'Content-Type: multipart/related',
      //'Content-Length: ' . mb_strlen(serialize($postdata), '8bit')
    );

    $post_string = json_encode($data);  

    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
    curl_setopt($curl, CURLOPT_URL, Config::GOOGLE_DRIVE_FILE_UPLOAD_URI . '?uploadType=multipart');
    //curl_setopt($curl, CURLOPT_BINARYTRANSFER, 1);
    curl_setopt($curl, CURLOPT_POST, 1);
    curl_setopt($curl, CURLOPT_POSTFIELDS, $postdata);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);

    $curlResponse = json_decode(curl_exec($curl), true);
    $responseCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);

    trigger_error("DEBUG: ".print_r($curlResponse, true));

    if ($responseCode != 200) 
    {
        $errorMessage = 'Failed to upload file to drive';
        if(curl_errno($curl)) 
        {
            $errorMessage = curl_error($curl);
        }
        throw new Exception('Error ' . $responseCode . ': ' . $errorMessage);
    }
    curl_close($curl);
    return $curlResponse['id'];
}

问题分析与解决方案

核心问题:Google Drive的multipart/related上传要求每个请求部分必须明确指定Content-Type,而用curl数组传递CURLOPT_POSTFIELDS时,curl会默认按multipart/form-data处理,且无法为metadata部分指定application/json类型,导致Drive无法识别元数据,进而触发错误。

以下是修正后的代码,手动构造符合要求的multipart/related请求体:

public function uploadFileToGoogleDriveMulti($accessToken, $filePath, $fileType, $fileName, $folderID)
{
    // 构造元数据JSON
    $metadata = json_encode([
        'name' => $fileName,
        'parents' => [$folderID] // 取消注释可指定上传目录
    ]);
    
    // 读取文件内容
    $fileContent = file_get_contents($filePath);
    if ($fileContent === false) {
        throw new Exception('Failed to read file: ' . $filePath);
    }
    
    // 生成随机边界字符串
    $boundary = '----GoogleDriveBoundary' . uniqid();
    
    // 构造multipart/related请求体
    $body = "--{$boundary}\r\n";
    $body .= "Content-Type: application/json; charset=UTF-8\r\n\r\n";
    $body .= $metadata . "\r\n";
    $body .= "--{$boundary}\r\n";
    $body .= "Content-Type: {$fileType}\r\n\r\n";
    $body .= $fileContent . "\r\n";
    $body .= "--{$boundary}--\r\n";
    
    $curl = curl_init();
    
    $headers = [
        'Authorization: Bearer ' . $accessToken,
        'Content-Type: multipart/related; boundary=' . $boundary,
        'Content-Length: ' . strlen($body)
    ];
    
    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true); // 生产环境建议开启SSL验证
    curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);
    curl_setopt($curl, CURLOPT_URL, Config::GOOGLE_DRIVE_FILE_UPLOAD_URI . '?uploadType=multipart');
    curl_setopt($curl, CURLOPT_POST, true);
    curl_setopt($curl, CURLOPT_POSTFIELDS, $body);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
    curl_setopt($curl, CURLOPT_BINARYTRANSFER, true); // 确保二进制文件正确传输
    
    $curlResponse = json_decode(curl_exec($curl), true);
    $responseCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
    
    trigger_error("DEBUG: ".print_r($curlResponse, true));
    
    if ($responseCode != 200) {
        $errorMessage = 'Failed to upload file to drive';
        if(curl_errno($curl)) {
            $errorMessage = curl_error($curl);
        }
        throw new Exception('Error ' . $responseCode . ': ' . $errorMessage);
    }
    
    curl_close($curl);
    return $curlResponse['id'];
}

关键修正点

  • 手动构造multipart/related请求体,明确为元数据部分指定application/json的Content-Type
  • 生成唯一边界字符串,确保请求体格式符合标准
  • 修复了不安全的SSL验证设置(生产环境建议保持开启)
  • 增加文件读取失败的异常处理
  • 启用CURLOPT_BINARYTRANSFER确保二进制文件正确传输

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 08:59:21