使用BlobStore的createUploadURL功能上传到GCS(Google云端存储)时,我可以提供回调以及将张贴到回调网址的标头数据。
使用GCS的signed URL's
似乎无法做到这一点我知道有Object Change Notification但是不允许用户在POST的标题中提供上传特定信息,就像使用createUploadURL的回调一样。
我的感觉是,如果createUploadURL能够做到这一点,必须有办法用签名的URL来做,但我找不到任何文档。我想知道是否有人可能知道createUploadURL如何实现回调调用行为。
PS:我正在尝试离开createUploadURL,因为它创建了__BlobInfo__
个实体,这对于我不需要的特定用例,并且似乎不可思议并且浪费存储空间。< / p>
更新: 有效!方法如下:
完成长答案:
如果你看看signed-URL页面,在HTTP_Verb前面,在 Description 下面,有一个微妙的说明,这个页面只与GET,HEAD,PUT和DELETE相关,但POST是一个完全不同的游戏。我错过了这个,但事实证明这非常重要。
整页HTTP Headers没有列出可以与POST一起使用的重要标题;该标题是success_action_redirect,因为voscausa正确回答。
在POST页面中,Google“强烈建议”使用PUT,除非处理表单数据。但是,POST有一些很好的功能,PUT没有。他们可能会担心POST给我们带来了太多的字符串,无法自拔。
但我要说完全值得删除createUploadURL,并编写自己的代码来重定向到回调。方法如下:
代码:
如果你在Python voscausa工作code非常有用。
我正在使用 apejs 在Java应用中编写javascript,所以我的代码如下所示:
var exp = new Date()
exp.setTime(exp.getTime() + 1000 * 60 * 100); //100 minutes
json['GoogleAccessId'] = String(appIdentity.getServiceAccountName())
json['key'] = keyGenerator()
json['bucket'] = bucket
json['Expires'] = exp.toISOString();
json['success_action_redirect'] = "https://" + request.getServerName() + "/test2/";
json['uri'] = 'https://' + bucket + '.storage.googleapis.com/';
var policy = {'expiration': json.Expires
, 'conditions': [
["starts-with", "$key", json.key],
{'Expires': json.Expires},
{'bucket': json.bucket},
{"success_action_redirect": json.success_action_redirect}
]
};
var plain = StringToBytes(JSON.stringify(policy))
json['policy'] = String(Base64.encodeBase64String(plain))
var result = appIdentity.signForApp(Base64.encodeBase64(plain, false));
json['signature'] = String(Base64.encodeBase64String(result.getSignature()))
上面的代码首先提供相关字段。 然后创建一个策略对象。然后它将字符串化为对象并将其转换为字节数组(您可以在Java中使用.getBytes。我必须为javascript编写一个函数)。 此数组的base64编码版本填充策略字段。 然后使用appidentity包进行签名。最后,签名是base64编码的,我们就完成了。
在客户端,json对象的所有成员都将添加到表单中,但 uri 除外,它是表单的地址。
var formData = new FormData(document.forms.namedItem('upload'));
var blob = new Blob([thedata], {type: 'application/json'})
var keys = ['GoogleAccessId', 'key', 'bucket', 'Expires', 'success_action_redirect', 'policy', 'signature']
for(field in keys)
formData.append(keys[field], url[keys[field]])
formData.append('file', blob)
var rest = new XMLHttpRequest();
rest.open('POST', url.uri)
rest.onload = callback_function
rest.send(formData)
如果您未提供重定向,则响应状态将为204以获得成功。但是如果你做重定向,状态将是200.如果你得到403或400有关签名或政策可能是错误的。看看responseText。如果通常有帮助。
需要注意的一些事项:
createUploadURL有什么问题?
上述方法是手动 createUploadURL 。 但是:
__BlobInfo__
个对象。这让我感到恼火,因为它浪费了很多空间(这让我想起了一个单独的问题:issue 4231。请给它一个明星)对于极少数的javascript app-engineers:
function StringToBytes(sz) {
map = function(x) {return x.charCodeAt(0)}
return sz.split('').map(map)
}
答案 0 :(得分:2)
使用GCS post对象时,可以在策略文档中包含succes_action_redirect。
文档:文档:https://cloud.google.com/storage/docs/xml-api/post-object
Python示例:https://github.com/voscausa/appengine-gcs-upload
示例回调结果:
def ok(self):
""" GCS upload success callback """
logging.debug('GCS upload result : %s' % self.request.query_string)
bucket = self.request.get('bucket', default_value='')
key = self.request.get('key', default_value='')
key_parts = key.rsplit('/', 1)
folder = key_parts[0] if len(key_parts) > 1 else None
答案 1 :(得分:0)
您可以在签名网址中包含以下标题:
HTTP Headers and Query String Parameters
例如,请参阅访问签名URL时如何请求返回特定的Content-Disposition标头:
public static String getSignedUrl(String httpVerb, String fileName, String gsKey) {
try {
long expiration = new Date().getTime()/1000 + 5 * 60 * 60;
String unsigned = stringToSign(expiration, gsKey, httpVerb);
String signature = sign(unsigned);
return new StringBuilder(BASE_URL).append("/")
.append(BUCKET)
.append("/")
.append(gsKey)
.append("?GoogleAccessId=")
.append(identityService.getServiceAccountName())
.append("&Expires=")
.append(expiration)
.append("&response-content-disposition=")
.append(URLEncoder.encode("attachment;filename=" + "\"" + fileName + "\"", "UTF-8"))
.append("&Signature=")
.append(URLEncoder.encode(signature, "UTF-8")).toString();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return null;
}
我希望它有所帮助 - 我想看看你是如何离开createUploadUrl的。
答案 2 :(得分:0)
我正在使用的解决方案是打开Object Changed Notifications。每次添加一个对象时,Post都会发送到一个URL - 在我的例子中 - 是我项目中的一个servlet。
在doPost()
中,我将所有被反对的信息添加到GCS中并从那里开始,我可以做任何事情。
这在我的App Engine项目中运行良好。