通过 API 上传本地 CSV 失败

Posted

技术标签:

【中文标题】通过 API 上传本地 CSV 失败【英文标题】:Uploading local CSV via API failing 【发布时间】:2012-08-04 00:16:07 【问题描述】:

我正在使用官方的 Google Ruby gem,虽然到目前为止我尝试过的所有其他操作都运行良好(包括列出项目、数据集和表以及创建表),但启动加载作业失败并出现以下问题在 JSON 错误响应中:

"Job configuration must contain exactly one job-specific configuration object (e.g., query, load, extract, spreadsheetExtract), but there were 0: "

我创建的正文字符串如下所示:

--xxx
Content-Type: application/json; charset=UTF-8
"configuration":"load":"destinationTable":"projectId":"mycompany.com:projectId","datasetId":"all_events","tableId":"install","createDisposition":"CREATE_NEVER","writeDisposition":"WRITE_APPEND"
--xxx
Content-Type: application/octet-stream
test,second,1234,6789,83838
--xxx

我之前已经为该数据创建了具有适当架构的 install 表,因此这应该不是问题。

最后,为了完整起见,这里是我用来触发请求的实际代码(这是更大类中的两种方法):

def create_insert_job
  config = 
    'configuration' => 
      'load' => 
        'destinationTable' => 
          'projectId' => 'mycompany.com:projectId',
          'datasetId' => 'all_events',
          'tableId' => 'install'
        ,
        'createDisposition' => 'CREATE_NEVER',
        'writeDisposition' => 'WRITE_APPEND'
      
    
  

  body = "#multipart_boundary\n"
  body += "Content-Type: application/json; charset=UTF-8\n"
  body += "#config.to_json\n"
  body += "#multipart_boundary\n"
  body +="Content-Type: application/octet-stream\n"
  body += "test,second,1234,6789,83838\n"
  body += "#multipart_boundary\n"

  prepare_big_query # This simply gets tokens and instantiates google_client and big_query_api
  param_hash =  api_method: big_query_api.jobs.insert 
  param_hash[:parameters] = 'projectId' =>'mycompany.com:projectId'
  param_hash[:body] = body
  param_hash[:headers] = 'Content-Type' => "multipart/related; boundary=#multipart_boundary"

  result = google_client.execute(param_hash)
  JSON.parse(result.response.body)
end

def multipart_boundary
  '--xxx'
end

有什么想法吗?

添加以下答案以使此代码有效

请注意,上面的#multipart_boundary 方法返回时已经添加了“--”。这是一个问题,因为设置边界标头(在参数哈希中)会在我们真正想要 'xxx' 时导致 '--xxx'。

此外,此 gem 的文档非常粗糙,因为在修复了我的换行问题(根据 @jcondit 的回答)后,我收到了一个关于上传到错误 URL 的新错误。那是因为您需要添加:

'uploadType' => 'multipart'

到参数,以便将请求发送到正确的 URL。

所以最终的 param_hash 有效(同样,在修复换行符和边界问题之后)看起来像:

param_hash =  api_method: big_query_api.jobs.insert 
param_hash[:parameters] = 'projectId' => project_id, 'uploadType' => 'multipart'
param_hash[:body] = body
param_hash[:headers] = 'Content-Type' => "multipart/related; boundary=#multipart_boundary"

【问题讨论】:

谢谢你! 2年后,这帮助了我。找不到我需要在参数中包含“uploadType”。 【参考方案1】:

您需要在每个 MIME 部分的标题和每个 MIME 部分的正文之间插入一个额外的换行符。您的请求正文应如下所示:

--xxx
Content-Type: application/json; charset=UTF-8

"configuration":"load":"destinationTable":"projectId":"mycompany.com:projectId","datasetId":"all_events","tableId":"install","createDisposition":"CREATE_NEVER","writeDisposition":"WRITE_APPEND"
--xxx
Content-Type: application/octet-stream

test,second,1234,6789,83838
--xxx--

注意每个部分中 Content-Type 标头后面的额外换行符。

另外,不要忘记最后的边界分隔符有一个尾随的 -- 附加到它。

【讨论】:

【参考方案2】:

您的 http 请求格式不正确 - bigquery 根本不会将其识别为加载作业。我正在出去吃晚饭的路上,所以我不能做任何更深入的调查,但希望这能给你一个继续前进的指导。

我仔细查看了一下,我认为您的请求没有任何问题。一个建议是尝试在 bigquery UI 中执行相同的加载,并使用 chrome 工具->开发者工具/网络选项卡查看发送的 RPC。

如果我使用虚拟 csv 文件执行此操作,我会得到:

--yql9f05215ct
Content-Type: application/json; charset=utf-8

"jobReference":"projectId":"helixdata2","configuration":"load":"destinationTable":"projectId":"helixdata2","datasetId":"lotsOdata","tableId":"import"
--yql9f05215ct
Content-Type: application/octet-stream
Content-Transfer-Encoding: base64

YSxiLGMKYyxkLGUKZixnLGgK
--yql9f05215ct--

【讨论】:

我看到的 3 个差异: - jobReference 键/值哈希 - Content-Transfer-Encoding: base64 - projectId 只是名称,而不是完整路径我尝试了两种方式的 porjectId 并添加到 jobReference 和内容传输。两者都失败了。请参阅下面的 cmets。 --xxx Content-Type: application/json; charset=UTF-8 "jobReference":"projectId":"wizards","configuration":"load":"destinationTable":"projectId":"wizards","datasetId":"all_events" ,"tableId":"install","createDisposition":"CREATE_NEVER","writeDisposition":"WRITE_APPEND" --xxx Content-Type: application/octet-stream Content-Transfer-Encoding: base64 test,second ,1234,6789,83838 --xxx --xxx Content-Type: application/json; charset=UTF-8 "jobReference":"projectId":"orangedoorarmory.com:wizards","configuration":"load":"destinationTable":"projectId":"orangedoorarmory.com:wizards" ,"datasetId":"all_events","tableId":"install","createDisposition":"CREATE_NEVER","writeDisposition":"WRITE_APPEND" --xxx Content-Type: application/octet-stream Content-传输编码:base64 test,second,1234,6789,83838 --xxx

以上是关于通过 API 上传本地 CSV 失败的主要内容,如果未能解决你的问题,请参考以下文章

上传 csv 并插入或更新结果失败

为啥在集群模式下读取 CSV 文件失败(而在本地工作正常)?

使用 Youtube REST API 上传视频失败

通过 Google Drive API 从本地 CSV 文件创建 Google Drive 电子表格

由于不支持的 API FindFirstFileEx(WACK 在本地传递)导致 UWP 应用提交失败

使用javascript通过google api发送邮件失败