尝试在 Google 云存储上上传 pdf 文件时出现 HttpError 400

HttpError 400 when trying to upload pdf file on Google Cloud Storage

我正在设置一项服务:

  1. 收到一封带有附件文件的电子邮件
  2. 将此文件上传到云存储
  3. 使用该文件作为进一步处理的来源

我到达了发生错误的第 2 步。我正在使用发现 API for Google 服务进行身份验证。我的是一个简单的烧瓶应用程序,下面是传入的电子邮件处理程序。

handle_incoming_email.py

__author__ = 'ciacicode'

import logging
import webapp2
from google.appengine.ext.webapp.mail_handlers import InboundMailHandler
from oauth2client.client import GoogleCredentials
from googleapiclient.discovery import build

credentials = GoogleCredentials.get_application_default()


class LogSenderHandler(InboundMailHandler):
    def receive(self, mail_message):
        logging.info("Received a message from: " + mail_message.sender)
        # upload attachment to cloud storage
        filename = 'any'
        try:
            attachment = mail_message.attachments
            filename = attachment[0].filename
            body = str(attachment[0].payload)
        except IndexError:
            print len(attachment)

        storage = build('storage', 'v1', credentials=credentials)
        req = storage.objects().insert(bucket='ocadopdf', body={'body': body, 'contentType': 'application/pdf', 'name': str(filename), 'contentEncoding': 'base64'})
        resp = req.execute()
        return resp


app = webapp2.WSGIApplication([LogSenderHandler.mapping()], debug=True)

向服务发送电子邮件后,我在日志中看到以下错误:

HttpError: https://www.googleapis.com/storage/v1/b/ocadopdf/o?alt=json returned "Upload requests must include an uploadType URL parameter and a URL path beginning with /upload/">

我知道信息没有发布到正确的端点,并且缺少 URL 参数,但是我在 Google 文档中挖掘得越多,就越难找到关于如何使用发现模块中的 .build 在服务 'storage'.

之前添加 URL 路径

-- 用解决方案更新 --

    file = cStringIO.StringIO()
    file.write(body)
    media = http.MediaIoBaseUpload(file, mimetype='application/pdf')
    storage = build('storage', 'v1', credentials=credentials)
    req = storage.objects().insert(bucket='ocadopdf', body={'name': str(filename), 'contentEncoding': 'base64'}, media_body=media)
    resp = req.execute()
    return resp`

我认为您的构建调用是正确的。此 example provides a good reference on how to upload a file to GCS as a new object. Instead of passing a file handle to MediaIoBaseUpload, you can pass a io.BytesIO containing the object contents as described in the MediaIoBaseUpload 文档