在问这个问题之前,我做了很多研究,也做了很多测试,像往常一样,我不喜欢仅仅因为。
我无法使用在浏览器中显示文件 (content-disposition:inline) 的 Java 创建签名网址。
当我使用 PHP sdk 执行时,我没有问题,我将签名的 url 复制并粘贴到浏览器中,文件在浏览器中显示。但是当对同一个文件使用java时,文件被下载。
在此 post 中,它提到了有关清晰元数据和将 "&response-content-disposition=inline" 附加到签名网址的内容,它也在 {{3} }}。
我尝试了多种方法,但是当我附加 google cloud docs 中指定的 "&response-content-disposition=inline" 时,我无法使其正常工作,我收到以下错误:
<Code>SignatureDoesNotMatch</Code>
<Message> The request signature we
calculated does not match the signature you provided. Check your
Google secret key and signing method. </Message>
但它说这些参数不包括在签名的计算中,所以我不知道发生了什么。
在我尝试过的代码中:
(transformed to kotlin)
val blobInfo = BlobInfo.newBuilder(BlobId.of(configuracion.bucket, fileName)).build()
val newMetadata: MutableMap<String, String> = HashMap()
newMetadata["contentDisposition"] = "inline"
blobInfo.toBuilder().setMetadata(newMetadata).build()
val signUrl = storage.signUrl(blobInfo, expiration, TimeUnit.MILLISECONDS,Storage.SignUrlOption.withV4Signature())
return signUrl.toString()
但没有运气。
我认为应该有一种非常直接的方法来将内容配置设置为我想要的任何内容,但似乎并非如此。
我生成签名网址的方式很简单:
val storage = this.getStorageDefaultInstance()
val blobInfo = BlobInfo.newBuilder(BlobId.of(configuracion.bucket, fileName)).build()
val signUrl = storage.signUrl(blobInfo, expiration, TimeUnit.MILLISECONDS, Storage.SignUrlOption.withV4Signature())
return signUrl.toString()
有什么建议吗?
编辑
我注意到,当我使用 PHP SDK 请求文件时,我得到响应标头 "content-type: application/pdf",而在 Java 上我得到 "content-type: application /octet-stream",也许这就是我需要改变的。
我尝试使用以下方法覆盖元数据:
val newMetadata: MutableMap<String, String> = HashMap()
newMetadata["contentDisposition"] = "inline"
newMetadata["contentType"] = "application%2Fpdf"
val blobInfo = BlobInfo.newBuilder(BlobId.of(configuracion.bucket, fileName)).setMetadata(newMetadata).build()
仍然没有运气。
答案 0 :(得分:1)
所以,
我一直在阅读和摆弄文档上的代码,直到我弄明白。
我阅读的越多,所有的阅读和研究开始变得更有意义。
所以如果以后有人遇到同样的问题,我最终用来改变响应头的代码是:
val storage = this.getStorageDefaultInstance()
val blobInfo = BlobInfo.newBuilder(BlobId.of(configuracion.bucket, fileName)).build()
//The query params
val queryParams: MutableMap<String, String> = HashMap()
queryParams["response-content-disposition"] = "inline"
queryParams["response-content-type"] = "application/pdf"
val signUrl = storage.signUrl(blobInfo, expiration, TimeUnit.MILLISECONDS,
Storage.SignUrlOption.withQueryParams(queryParams), //This is the magic line
Storage.SignUrlOption.withV4Signature())
return signUrl.toString()
为了更清楚,当我阅读其他帖子和文档时,关于将参数(response-content-disposition 和 response-content-type ),我尝试了多种方式,在评论中的某处我阅读 response-content-disposition 是不够的,这对我来说是这种情况,我还需要添加 response-content -type 也是,但我的主要错误是在 url 签名后附加这些。
在对 url 进行签名之前,您需要创建 url 并将参数附加到查询字符串中(上面的示例代码),并且 google api 将返回签名的 url,包括附加在查询字符串中的带有指定值的两个参数,所以后面不需要修改url,就可以使用了。
希望这有助于其他人节省时间。
答案 1 :(得分:0)
这是我运行的代码,它会生成 pdf 的签名 url,然后在浏览器中呈现,如果这对您不起作用,我会查看 pdf 或浏览器设置。
String projectId = "<project_name>";
String bucketName = "<bucket_name>";
String objectName = "<file_name>";
Storage strg = StorageOptions.newBuilder().setProjectId(projectId).build().getService();
BlobInfo blobinfo = BlobInfo.newBuilder(BlobId.of(bucketName, objectName)).build();
FileInputStream key = new FileInputStream("<path_to_json>");
URL url = strg.signUrl(blobinfo,
1, TimeUnit.MINUTES, Storage.SignUrlOption.withV4Signature(),
SignUrlOption.signWith(ServiceAccountCredentials.fromStream(key))
);
System.out.println("Signed URL:");
System.out.println(url);