【问题标题】:Can't upload to BigQuery from Perl无法从 Perl 上传到 BigQuery
【发布时间】:2013-08-06 21:51:45
【问题描述】:

我正在尝试使用示例架构和一些示例数据从 Perl 上传到 BigQuery。我在他们提供的文档之后遇到了死胡同,所以现在我正在尝试模仿bq 命令行客户端成功完成的工作。

我通过在httplib2 中的request 方法中添加调试print (method, uri, headers, body) 来跟踪bq 所做的事情。我通过在响应上执行Dumper 来跟踪我的Perl 库正在做什么,其中还包括我发送的_requestbq 中的模式是他们 POST 到一个上传 URL,然后返回一个 locationPUT 数据到。通过一系列GET 请求监控相应的作业,最后它们做出响应。

在 Perl 中,我的 POST 成功,而我的 GET 失败并显示 Invalid Upload Request(但没有提示为什么它无效)。我试图弄清楚两者之间的差异可以解释我的失败。但我找不到。

这里是(省略了 access_token、IP 地址和 project_id)我得到的踪迹。

对于POST,来自 Python 的信息是:

(
    u'POST',
    u'https://www.googleapis.com/upload/bigquery/v2/projects/<project ID>/jobs?uploadType=resumable&alt=json',
    {
        'content-length': '442',
        'accept-encoding': 'gzip, deflate',
        'accept': 'application/json',
        'user-agent': u'bq/2.0 google-api-python-client/1.0',
        'X-Upload-Content-Length': '84',
        'X-Upload-Content-Type': 'application/octet-stream',
        'content-type': 'application/json',
        'Authorization': u'Bearer <access token>'
    },
    '{"configuration": {"load": {"sourceFormat": "NEWLINE_DELIMITED_JSON", "destinationTable": {"projectId": "<project id>", "tableId": "demo_api", "datasetId": "tmp_bt"}, "maxBadRecords": 0, "schema": {"fields": [{"type": "STRING", "mode": "required", "name": "demo_string"}, {"type": "INTEGER", "mode": "required", "name": "demo_integer"}]}}}, "jobReference": {"projectId": "<project id>", "jobId": "bqjob_r139e633b7e522cf7_0000014031d9fb49_1"}}'
)

对应的 Perl 得到一个明显成功的响应对象(你可以在其中看到_request):

$VAR1 = bless( {
    '_protocol' => 'HTTP/1.1',
    '_content' => '',
    '_rc' => '200',
    '_headers' => bless( {
        'connection' => 'close',
        'client-response-num' => 1,
        'location' => 'https://www.googleapis.com/upload/bigquery/v2/projects/<project id>/jobs?uploadType=resumable&upload_id=AEnB2Ur0mdwmZpMot6ftkgj1IkqK0f7oPbZrXWQekUDHK_E2o2HKznJO6DK2xPYCB-nhUGrMrEJJ7z1Tz9Crnka9e5EYGP1lWQ',
        'date' => 'Tue, 06 Aug 2013 20:46:05 GMT',
        'client-ssl-cert-issuer' => '/C=US/O=Google Inc/CN=Google Internet Authority',
        'client-ssl-cipher' => 'RC4-SHA',
        'client-peer' => '<some ip>:443',
        'content-length' => '0',
        'client-date' => 'Tue, 06 Aug 2013 20:46:05 GMT',
        'content-type' => 'text/html; charset=UTF-8',
        'client-ssl-cert-subject' => '/C=US/ST=California/L=Mountain View/O=Google Inc/CN=*.googleapis.com',
        'server' => 'HTTP Upload Server Built on Jul 24 2013 17:20:01 (1374711601)',
        'client-ssl-socket-class' => 'IO::Socket::SSL'
    }, 'HTTP::Headers' ),
    '_msg' => 'OK',
    '_request' => bless( {
        '_content' => '{"configuration":{"load":{"maxBadRecords":0,"destinationTable":{"datasetId":"tmp_bt","tableId":"perl","projectId":<project id>},"sourceFormat":"NEWLINE_DELIMITED_JSON","schema":{"fields":[{"mode":"required","name":"demo_string","type":"STRING"},{"mode":"required","name":"demo_integer","type":"INTEGER"}]}}},"jobReference":{"projectId":<project id>,"jobId":"perlapi_1375821964"}}',
        '_uri' => bless( do{\(my $o = 'https://www.googleapis.com/upload/bigquery/v2/projects/<project id>/jobs?uploadType=resumable')}, 'URI::https' ),
        '_headers' => bless( {
            'user-agent' => 'libwww-perl/6.05',
            'content-type' => 'application/json',
            'accept' => 'application/json',
            ':X-Upload-Content-Type' => 'application/octet-stream',
            'content-length' => 379,
            ':X-Upload-Content-Length' => '84',
            'authorization' => 'Bearer <access token>'
        }, 'HTTP::Headers' ),
        '_method' => 'POST',
        '_uri_canonical' => $VAR1->{'_request'}{'_uri'}
    }, 'HTTP::Request' )
}, 'HTTP::Response' );

然后我们有一个PUT。在我们发送的 Python 端:

(
    'PUT',
    'https://www.googleapis.com/upload/bigquery/v2/projects/<project id>/jobs?uploadType=resumable&alt=json&upload_id=AEnB2UpWMRCAOffqyR0d7zvGVtD-KWhrC9jGB-q_igecJgoyz_mIHgEFfs9cYoPxUwUxuflQScMzGxDsKKJ_CJPQq4Os-AkdZA',
     {
         'Content-Range': 'bytes 0-83/84',
         'Content-Length': '84',
         'Authorization': u'Bearer <access token>',
         'user-agent': u'bq/2.0'
    },
    <apiclient.http._StreamSlice object at 0x10ce11150>
)

(我已经验证了流切片对象与 Perl 具有相同的 84 个字节。)这是 Perl 的失败:

$VAR1 = bless( {
    '_protocol' => 'HTTP/1.1',
    '_content' => '{
 "error": {
  "errors": [
   {
    "domain": "global",
    "reason": "badRequest",
    "message": "Invalid Upload Request"
   }
  ],
  "code": 400,
  "message": "Invalid Upload Request"
 }
}
',
    '_rc' => '400',
    '_headers' => bless( {
        'connection' => 'close',
        'client-response-num' => 1,
        'date' => 'Tue, 06 Aug 2013 20:46:07 GMT',
        'client-ssl-cert-issuer' => '/C=US/O=Google Inc/CN=Google Internet Authority',
        'client-ssl-cipher' => 'RC4-SHA',
        'client-peer' => '<some IP address>:443',
        'content-length' => '193',
        'client-date' => 'Tue, 06 Aug 2013 20:46:07 GMT',
        'content-type' => 'application/json',
        'client-ssl-cert-subject' => '/C=US/ST=California/L=Mountain View/O=Google Inc/CN=*.googleapis.com',
        'server' => 'HTTP Upload Server Built on Jul 24 2013 17:20:01 (1374711601)',
        'client-ssl-socket-class' => 'IO::Socket::SSL'
    }, 'HTTP::Headers' ),
    '_msg' => 'Bad Request',
    '_request' => bless( {
        '_content' => '{"demo_string":"foo", "demo_integer":"2"}
{"demo_string":"bar", "demo_integer":"3"}
',
        '_uri' => bless( do{\(my $o = 'https://www.googleapis.com/upload/bigquery/v2/projects/<project id>/jobs?uploadType=resumable&upload_id=AEnB2Ur0mdwmZpMot6ftkgj1IkqK0f7oPbZrXWQekUDHK_E2o2HKznJO6DK2xPYCB-nhUGrMrEJJ7z1Tz9Crnka9e5EYGP1lWQ')}, 'URI::https' ),
        '_headers' => bless( {
            'user-agent' => 'libwww-perl/6.05',
            ':Content-Length' => '84',
            ':Content-Range' => '0-83/84',
            'content-length' => 84,
            'authorization' => 'Bearer <access token>'
        }, 'HTTP::Headers' ),
        '_method' => 'PUT',
        '_uri_canonical' => $VAR1->{'_request'}{'_uri'}
    }, 'HTTP::Request' )
}, 'HTTP::Response' );

我应该尝试在 Perl 方面进行哪些更改以使 BigQuery 像对 bq 一样响应我?

【问题讨论】:

    标签: google-api google-bigquery google-api-client


    【解决方案1】:

    您的一些 PUT 标头前面有冒号,而 Python 没有:

    ':Content-Length' => '84',
    ':Content-Range' => '0-83/84',
    

    【讨论】:

    • 这些冒号不会影响我的结果。让它们在那里告诉 HTTP::Headers 不要规范化标头的大小写。我希望强制使用与 Python 相同的大小写会有所帮助,但它没有。也就是说,如果 BigQuery 通过使标头区分大小写而违反了ietf.org/rfc/rfc2616.txt,那么我将需要一个需要大写字母的列表,在哪里。
    【解决方案2】:

    我怀疑分段上传请求中存在格式错误。错误“无效的上传请求”是对尝试将数据有效负载从多部分 mime 消息中拆分出来的响应。您的日志记录不包含请求正文的详细信息,因此我们无法并排比较它们是否存在意外差异。

    为确保问题出在分段上传,您可以尝试从 Google 存储加载数据的加载请求,而不是将数据包含在请求负载本身中。这将验证 perl api 请求路径是否适合您。

    仅供参考:有一个 alpha Perl Google API 客户端可以帮助您。我没有尝试过,也不知道它是否正在积极开发中,但你可能会在那里找到一些有用的提示。查看https://code.google.com/p/google-api-perl-client/

    【讨论】:

    • Perl 中的主体是逐字节的,与 Python 版本中 httplib2request 方法内部的 body 的内容相同。您是否建议 Python 会查看它是一个帖子这一事实,并在它到达您的服务之前更改该正文?
    • 我会看看那个客户。一目了然,它是 alpha 版,直到最近才添加了对上传的任何支持。但值得一试。
    猜你喜欢
    • 2017-12-03
    • 2021-10-19
    • 1970-01-01
    • 2020-12-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多