无法成功上传文件使用签名的URL到谷歌云存储从高级REST客户端
我想创建一个签名的URL,并从我的电脑上传文件到谷歌云存储使用它。无法成功上传文件使用签名的URL到谷歌云存储从高级REST客户端
我正在使用高级REST客户端(ARC)作为客户端应用程序。在服务器端,我有一个在Appengine上运行的基于球衣的服务器。
我首先从ARC发送一个GET请求,接收哪个app引擎生成一个签名的URL并将它返回给响应。
之后,我做了一个PUT请求,我要在正文中上传文件,请求URL设置为在GET响应中收到的内容。
的代码片断创建签署网址:
String encodedUrl = null;
String contentMD5 = "";
String contentType = "";
String httpVerb;
httpVerb = "PUT";
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.MINUTE, 10);
long expiration = calendar.getTimeInMillis()/1000L;
String canonicalizedResource = "/" + bucketName + "/" + objectName;
String baseURL = "https://storage.googleapis.com" + canonicalizedResource;
String stringToSign =
httpVerb + "\n" + contentMD5 + "\n" + contentType + "\n" + expiration + "\n"
+ canonicalizedResource;
AppIdentityService service = AppIdentityServiceFactory.getAppIdentityService();
String googleAccessId = service.getServiceAccountName();
SigningResult signingResult = service.signForApp(stringToSign.getBytes());
String encodedSignature = null;
try {
encodedSignature =
new String(Base64.encodeBase64(signingResult.getSignature(), false), "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new InternalServerErrorException();
}
String signature = null;
try {
signature = URLEncoder.encode(encodedSignature, "UTF-8").toString();
} catch (UnsupportedEncodingException e) {
throw new InternalServerErrorException();
}
encodedUrl =
baseURL + "?GoogleAccessId=" + googleAccessId + "&Expires=" + expiration
+ "&Signature=" + signature;
System.out.println("Signed URL is: "+encodedUrl);
但是我观察了以下问题:
-
每当我发送任何文件类型的PUT请求,我得到以下错误:
错误 - 403
码 - SignatureDoesNotMatch消息 - 我们计算的请求签名与您提供的签名不匹配。检查您的Google秘密密钥和签名方法
请注意,在我的代码中,我在创建要签名的字符串时将内容类型设置为“”。同时创建PUT请求时,我不包含任何Content-type标头。
据我所知,如果我在创建签名URL时不在stringToSign中包含contentType,并且在发送PUT请求时没有将其作为头添加,它应该没问题。那么错误的原因是什么?
- 之后,我通过代码进行了更改,并在代码中创建stringToSign时添加了contentType,并在发送PUT请求时给出了相应的Content-Type头。
在这种情况下,我可以上传文件,但上传的文件被修改/损坏。我尝试使用text/plain和image/jpeg。
的问题是,下面的文字是在文件的开头说:
------WebKitFormBoundaryZX8rPPhnm1WXPrUf
Content-Disposition: form-data; name="fileUpload5"; filename="blob"
Content-Type: text/plain
我可以在文本文件,并在十六进制编辑器打开.jpg文件看到这一点。 .jpg在标准图像应用程序中无法打开,因为文件已被开头的文本损坏
我在这里丢失了什么吗?这是高级REST客户端中的任何问题吗? 实际上,无论何时我发送PUT请求与正文中的某个文件,我都会在ARC中收到一条消息: 内容类型标题将在发送请求时最终更改为multipart/form-data 但是,我保存将所有消息导出到ARC的文件中,但没有发现任何Content-type头部设置为multipart/form-data的消息。 那么为什么这个消息来了,它实际上是一个问题?
网址签名的代码是棘手和非常难以调试。幸运的是,谷歌的谷歌云库有一个signUrl
函数为您处理这件事。我强烈建议你使用它,而不是自己重写它。 Here's the documentation。现在
,如果你想自己调试它,检查错误消息是超级有用。它将包括服务器检查签名的字符串的完整副本。打印出你的stringToSign
变量,看看它有什么不同。那会告诉你什么是错的。
现在,您的具体问题:它听起来像你生成一个可以接受已签署的网址,但后来您的客户尝试就好像它是做多,形式上传上传到GCS。您正在查看的文本是HTTP多部分请求的一部分,“multipart/form-data”警告也指出了该方向。看看您使用的应用程序是否有某种您可能意外使用的“表单”模式/选项?
谢谢。正如您所提到的那样,高级REST客户端似乎存在一些问题,因为即使指定了其他内容类型,它也会将上载作为多部分表单数据进行上传。我找不到如何更改设置,但我现在使用curl命令行工具进行上传/下载,并且工作正常。 –