【发布时间】:2017-06-20 00:56:30
【问题描述】:
我打算让我的应用程序的用户将文件直接上传到 GCS,为此我使用带有签名 URL 的 PUT request。我在 python 中的代码如下所示:
def get(self):
base_url = 'https://storage.googleapis.com/' + self.get_bucket_name()
expiration = utils.unix_time_secs(datetime.now() + timedelta(hours=1))
string_to_sign = ( 'PUT' + "\n" +
'' + "\n" +
'' + "\n" +
str(expiration) + "\n" +
'' + "\n" +
'my-bucket.appspot.com')
signed_string = app_identity.sign_blob(string_to_sign)[1]
signature = base64.b64encode(signed_string)
signature = urllib.quote(signature, safe='')
google_access_id = app_identity.get_service_account_name()
params = '?GoogleAccessId={0}&Expires={1}&Signature={2}'.format(
google_access_id, expiration, signature)
self.template_values['base_url'] = base_url
self.template_values['params'] = params
self.render('testA.html')
在客户端,我使用 XMLHttpRequest 将文件发送到 GCS:
function gCloud (base_url, params, callback) {
var xhr = new XMLHttpRequest();
var file = document.querySelector('#fotos').files[0]
//Here goes an event listener (callback)
url = base_url + '/' + file.name + params
xhr.open("PUT", url, true);
xhr.setRequestHeader("Content-Type", file.type)
xhr.send(file)
}
问题是,当我发送此请求时,我收到一个 403 禁止错误,表示计算的签名与我提供的签名不匹配。这可能是一个愚蠢的错误,但我无法让它工作。可能是什么问题?
编辑:
我尝试使用 google-cloud-python,并尝试了这段代码(有效):
def get(self):
bucket = storage.Client().get_bucket(self.get_bucket_name())
blob = bucket.blob('Yosemite.jpg')
expiration = utils.unix_time_secs(datetime.now() + timedelta(hours=1))
base_url = blob.generate_signed_url(expiration, "PUT", 'image/jpeg')
self.template_values['base_url'] = base_url
self.render('testA.html')
现在的问题是,由于 'generate_signed_url' 是 Blob 类的一个方法,它已经假定我知道创建 url 的对象的唯一路径,例如 blob = bucket.blob('Yosemite.jpg'),我没有。如果用户想上传 Space.jpg 怎么办? Yosemite.jpg 不会创建 my-bucket/Space.jpg,而是会被覆盖,所以我将拥有 Yosemite.jpg,如果我打开图像,它实际上是 Space.jpg。我该如何解决这个问题?
另外,如果我在 'generate_signed_url' 函数中不包含 Content-Type='image-jpeg',签名将不匹配。如果用户上传的是 png 怎么办?
【问题讨论】:
标签: python google-app-engine google-cloud-storage