当前位置: 首页 > 知识库问答 >
问题:

如何将谷歌云存储中的不同文件类型推送到客户端浏览器?

嵇财
2023-03-14

我试图使用Google云存储(GCS)、Python2.7和Ferris框架创建一个文档管理系统。我能够将许多类型的文件上传到云存储中,并且能够以编程方式将CSV和TXT推送到客户端浏览器下载,没有任何问题。但是,如果该文件是Microsoft Word文档、PDF或任何其他MIME类型,我会不断得到以下错误:

'ascii' codec can't decode byte 0xe2 in position X
    @route
    def test_get_csv_file(self):
        # the file in google cloud storage
        thefilename = '/mydomain.appspot.com/my_csv_file.csv'
        try:
            with gcs.open(thefilename, "r") as the_file:
            self.response.headers["Content-Disposition"] = "'attachment'; filename=my_csv_file.csv"
            return the_file.read(32*1024*1024).decode("utf-8")
        except gcs.NotFoundError:
            return "it failed" 
@route
def test_get_word_file(self):
    # the file in google cloud storage
    thefilename = '/mydomain.appspot.com/my_word_file.doc'
    try:
        with gcs.open(thefilename, "r") as the_file:
            self.response.headers["Content-Disposition"] = "'attachment'; filename=my_word_file.doc"
            return the_file.read(32*1024*1024).decode("utf-8")
    except gcs.NotFoundError:
        return "it failed" 

对文件的访问必须限制在域帐户,所以我不能将bucket的默认ACL设置为public-read,否则我只会使用storage.googlapis.com/yadda/yadda URL作为服务URL并使用它。我还尝试将decode值更改为Latin-1,但这只是呈现一个空白文件。我不明白为什么这与CSV文件工作,而不是其他任何东西。我很感激任何帮助。谢谢

共有1个答案

南门飞
2023-03-14

它并不能真正解决你的问题。但另一种方法是使用签名URL。然后,这些文件将直接从云存储中提供,生成的url将在有限的时间内有效。

我使用下面的python模块。它有一些用于url签名的实用方法和类。

import datetime
import time
import urllib
from urlparse import urlparse

__author__ = 'fabio'
__all__ = ['sign', 'PolicyDocument', 'CloudStorageURLSigner']

from google.appengine.api import app_identity
from base64 import b64encode
import json


def sign(string_to_sign):
    signing_key_name, signature = app_identity.sign_blob(string_to_sign)
    return b64encode(signature)


class PolicyDocument:
    """Represents a policy.

    Attributes:
        content_type:
        success_action_redirect:
        key:
        bucket:
        expiration:
        acl:
        success_action_status:
    """
    ACL = "acl"
    SUCCESS_ACTION_REDIRECT = "success_action_redirect"
    SUCCESS_ACTION_STATUS = "success_action_status"
    KEY = "key"
    BUCKET = "bucket"
    CONTENT_TYPE = "content-type"
    ACL_PUBLIC_READ = "public-read"
    ACL_PROJECT_PRIVATE = "project-private"

    def __init__(self, content_type=None, success_action_redirect=None, key=None, bucket=None, expiration=None,
                 success_action_status=201, acl=ACL_PROJECT_PRIVATE):
        self.content_type = content_type
        self.success_action_redirect = success_action_redirect
        self.key = key
        self.bucket = bucket
        self.expiration = expiration
        self.acl = acl
        self.success_action_status = success_action_status

    def as_dict(self):
        conditions = [{self.ACL: self.acl},
                      {self.BUCKET: self.bucket},
                      {self.KEY: self.key},
                      {self.CONTENT_TYPE: self.content_type},
                      ["starts-with", "$content-type", 'image/'],
        ]

        # TODO investigate why its not working
        if self.success_action_redirect:
            conditions.append({self.SUCCESS_ACTION_REDIRECT: self.success_action_redirect})
        else:
            conditions.append({self.SUCCESS_ACTION_STATUS: str(self.success_action_status)})

        return dict(expiration=self.expiration, conditions=conditions)

    def as_json_b64encode(self):
        return b64encode(self.as_json())

    def as_json(self):
        return json.dumps(self.as_dict())


class CloudStorageURLSigner(object):
    """Contains methods for generating signed URLs for Google Cloud Storage."""

    DEFAULT_GCS_API_ENDPOINT = 'https://storage.googleapis.com'

    def __init__(self, gcs_api_endpoint=None, expiration=None):
        """Creates a CloudStorageURLSigner that can be used to access signed URLs.
    Args:
      gcs_api_endpoint: Base URL for GCS API. Default is 'https://storage.googleapis.com'
      expiration: An instance of datetime.datetime containing the time when the
                  signed URL should expire.
    """
        self.gcs_api_endpoint = gcs_api_endpoint or self.DEFAULT_GCS_API_ENDPOINT
        self.expiration = expiration or (datetime.datetime.now() +
                                         datetime.timedelta(days=1))
        self.expiration = int(time.mktime(self.expiration.timetuple()))
        self.client_id_email = app_identity.get_service_account_name()

    def __make_signature_string(self, verb, path, content_md5, content_type):
        """Creates the signature string for signing according to GCS docs."""
        signature_string = ('{verb}\n'
                            '{content_md5}\n'
                            '{content_type}\n'
                            '{expiration}\n'
                            '{resource}')
        return signature_string.format(verb=verb,
                                       content_md5=content_md5,
                                       content_type=content_type,
                                       expiration=self.expiration,
                                       resource=path)

    def signed_url(self, verb, path, content_type='', content_md5=''):
        """Forms and returns the full signed URL to access GCS."""
        base_url = '%s%s' % (self.gcs_api_endpoint, path)
        signature_string = self.__make_signature_string(verb, path, content_md5,
                                                        content_type)
        signature = urllib.quote_plus(sign(signature_string))
        return "{}?GoogleAccessId={}&Expires={}&Signature={}".format(base_url, self.client_id_email,
                                                                     str(self.expiration), signature)

    def signed_download_url(self, url):
        if self.is_stored_on_google_cloud_storage(url):
            parsed_url = urlparse(url)
            return self.signed_url('GET', parsed_url.path)
        return url

    @staticmethod
    def is_stored_on_google_cloud_storage(url):
        return "storage.googleapis.com" in url
 类似资料:
  • 问题内容: 我想创建一个应用程序,当超级用户单击链接时,用户应该获得通知或类似pdf的内容,以便他们在屏幕上访问。 用例:当教师想与他的学生共享PDF时,他应该能够通知他的学生有关可下载的pdf的信息,并且必须提供一个链接来做到这一点。 问题答案: 当您想在CakePHP中实现此功能(因此我假设它是基于Web的应用程序)时,用户必须打开“活动”页面才能接收推送消息。 值得一看前两个答案,但也只需考

  • 我正在尝试使用谷歌云存储JSON API将图像上传到谷歌云存储桶中。文件正在上载,但没有显示任何内容。 我正在通过以下方式上载图像:- 图像1 看图片1,文件上传成功。但当我点击它查看它时,它显示如图2所示。 图像2

  • 我需要在谷歌云存储中“作为最终用户进行身份验证”(我代表我的应用程序的最终用户访问资源)。因为我的应用程序是用C++编写的。我编译了C++谷歌云存储客户端库。但是这里它声明它需要客户端的JSON文件来创建GCS::Client对象。我找不到任何其他方法来创建带有项目id、服务电子邮件、私钥、密钥名和桶名等信息的客户端(这些信息足以在python中进行身份验证)。有没有办法在谷歌云存储C++客户端库

  • 我目前面临的问题与谷歌云存储, 我能够下载对象上传到谷歌云存储,但当天晚些时候,我开始得到的错误,因为"这个网站无法到达" 我在c#中以编程方式创建了一个bucket,代码如下: 因此,创建存储桶的设置如下: 默认存储类别:多地区 位置:美国(美国多个地区) 公共访问:每个对象 生命周期:无 访问控制模型:存储桶策略

  • 我想按照官方文档中提供的示例将一个文件上传到Google云存储 然而,我得到了一个错误: 线程“main”com.google.cloud.storage.StorageException中的异常:获取服务帐户的访问令牌时出错:400个错误请求{“错误”:“无效的授予”、“错误描述”:“无效的JWT:令牌必须是短期令牌(60分钟)并且在合理的时间范围内。请检查JWT声明中的iat和exp值。”位于

  • 我有一个谷歌云,我想推我的图像。 我的图片是Hello-world项目与节点快递谷歌云客户端libray 你可以在我的github上找到它 https://github.com/innostarterkit/language 当我试着推的时候,我有这个错误 推送是指存储库[eu.gcr.io/innovation xxx/hello]a419c4413fb0:推送[================