如何在GAE中从GCS提供pdf文件?

时间:2015-02-04 07:23:10

标签: python google-app-engine google-cloud-storage

我在Python中使用Google App Engine来处理小型网络应用程序。

我有一些文件存储在我的GCS中,只有在用户登录时才能提供。

我虽然这很容易,但是我确实因为我的代码而错过了一步:

import cloudstorage as gcs

class Handler(webapp2.RequestHandler):
    def write(self, *a, **kw):
        self.response.out.write(*a, **kw)

class testHandler (Handler):
    def get (self):
        bucket = '/my_bucket'
        filename = '/pdf/somedoc.pdf'
        user = users.get_current_user()
        if user:
            pdf = gcs.open(bucket+filename)
            self.write(pdf)

只给出:

<cloudstorage.storage_api.ReadBuffer object at 0xfbb931d0>

我需要的是文件本身。

任何人都可以告诉我,我错过了哪一步?

由于

3 个答案:

答案 0 :(得分:1)

经过一番思考,淋浴和喝咖啡后,我发现自己有两个问题。

首先我写的是文件的地址,而不是文件。

所以正确的电话会是:

self.write(pdf.read())

另外,我必须将'Content-Type'标题更改为'application / pdf',以允许浏览器提供文件而不是文本文件。

无论如何,结果是:

class pHandler(webapp2.RequestHandler):
    def write(self, *a, **kw):
        self.response.headers['Content-Type']='application/pdf'
        self.response.out.write(*a, **kw)

class testHandler (pHandler):
    def get (self):
        bucket = '/my_bucket'
        filename = '/pdf/somedoc.pdf'
        user = users.get_current_user()
        if user:
            pdf = gcs.open(bucket+filename)
            self.write(pdf.read())

答案 1 :(得分:1)

即使是PO回答了他的问题,也只是想补充几点想法。

PO的代码是将pdf文件的内容写入http响应。

self.write(pdf.read())

根据GAE quota limitation,如果响应大小大于32MB,则会失败。

此外,最好设置urlfetch_timeout值,因为在某些情况下默认值5秒可能不够,并且会导致DeadlineExceededError

我建议您在收到请求时尝试使用Google Cloud Storage API(不是GAE)将copy文件发送到临时位置。还要确保将新对象的acl设置为公共可读,然后提供新对象的公共URL。

此外,向任务队列发送请求,将任务的eta设置为您选择的超时值。执行任务后,从临时位置删除该文件,以便无法再访问该文件。

更新:

使用Service Account Auth,生成新的JSON密钥,获取私钥。

将范围设置为FULL_CONTROL,因为我们需要更改acl设置。

我在工作时还没有测试代码。但是,当我有时间的时候会这样做。

import httplib2
from apiclient.discovery import build
from apiclient.errors import HttpError
from oauth2client.client import SignedJwtAssertionCredentials


# Need to modify ACL, therefore need full control access
GCS_SCOPE = 'https://www.googleapis.com/auth/devstorage.full_control'


def get_gcs_client( project_id, 
                    service_account=None,
                    private_key=None):

    credentials = SignedJwtAssertionCredentials(service_account, private_key, scope=GCS_SCOPE)

    http = httplib2.Http()
    http = credentials.authorize(http)
    service = build('storage', 'v2', http=http)

    return service

答案 2 :(得分:0)

我认为您最好在GCS上使用BlobStore API来提供此类文件。基于Using the Blobstore API with Google Cloud Storage,我提出了这种方法:

import cloudstorage as gcs
import webapp2

from google.appengine.ext import blobstore
from google.appengine.ext.webapp import blobstore_handlers

GCS_PREFIX = '/gs'
BUCKET = '/my_bucket'
FILE = '/pdf/somedoc.pdf'
BLOBSTORE_FILENAME = GCS_PREFIX + BUCKET + FILE

class GCSWebAppHandler(webapp2.RequestHandler):
    def get(self):
        blob_key = blobstore.create_gs_key(BLOBSTORE_FILENAME)
        self.response.headers['Content-Type'] = 'application/pdf'
        self.response.write(blobstore.fetch_data(blob_key, 0, blobstore.MAX_BLOB_FETCH_SIZE - 1))

class GCSBlobDlHandler(blobstore_handlers.BlobstoreDownloadHandler):
    def get(self):
        blob_key = blobstore.create_gs_key(BLOBSTORE_FILENAME)
        self.send_blob(blob_key)

app = webapp2.WSGIApplication([
    ('/webapphandler', GCSWebAppHandler),
    ('/blobdlhandler', GCSServingHandler)],
    debug=True)

如您所见,您可以在此处使用两个示例处理程序,webapphandlerblobdlhandler。使用后者可能会更好,因为前者受MAX_BLOB_FETCH_SIZEfetch_data()的限制,即1MB,但如果您提供的文件小于此大小,则可以