如何防止 Akka Http 重定向请求中 URI 的百分比解码?
How to prevent percent decoding of URIs in Akka Http redirect requests?
我正在使用 Akka Http 为存储在 GCS(Google 云存储)中的文本资源处理签名 url 的重定向。基本上我在 GCS 中有一些文件,我想在请求时与我的 API 一起交付。不幸的是,这个资源的路径有一个子目录,里面有一个 =
字符,比如:https://storage.googleapis.com/path_start/more_path/format=avro/still_more_path/filename.avro
.
Google 存储的 signUrl
方法百分比将此 =
字符编码为签名 url 中的 %3D
。我已经验证使用这个签名 url 允许访问 GCS 中的文件(点击它开始下载)。问题是当 Akka Http 根据请求重定向这个带符号的 url 时,它会将其解码回等号。这会导致 GCS 出现 SignatureDoesNotMatch
错误:
<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>
我尝试生成已签名的 url 并在以下代码片段中重定向它:
val signedUrl = cloudStorageService.getSignedUrl(bucketId, filePath)
logger.info(s"signedUrl: $signedUrl")
redirect(signedUrl, TemporaryRedirect)
和我的cloudStorageService.getSignedUrl
方法在这里单独定义:
def getSignedUrl(bucket: String, path: String, expiration: Option[Int] = None): String = {
val maxLifetime = 60 * 60 * 24 * 7
val lifetime = expiration.getOrElse(maxLifetime)
val cappedExpiration = Math.min(lifetime, maxLifetime)
val blobInfo = BlobInfo.newBuilder(BlobId.of(bucket, path)).build
storage.signUrl(blobInfo, cappedExpiration, TimeUnit.SECONDS, Storage.SignUrlOption.withV4Signature).toString
}
第一个片段中的日志记录语句显示带符号的 URL 是使用 %3D
生成的,但是重定向的 URL 已被百分比解码回 =
,导致 SignatureDoesNotMatch
错误。
此行为是 Akka Http 的标准行为。根据 the documentation for Uri class,所有成员都表示已解码元素的百分比。可以选择使用原始查询字符串构造 uri,但在我的例子中,编码字符出现在 uri 路径本身,而不是查询中。
所以我的问题是,有没有办法让 Akka Http 重定向这个签名的 url 而无需百分比解码路径?还是我弄错了,还有另一种方法可以解决这个问题?
您可能想要创建重定向响应 'manually' 而不是使用 'redirect' 指令。指令实现为:
HttpResponse(
status = redirectionType,
headers = headers.Location(uri) :: Nil,
entity = redirectionType.htmlTemplate match {
case "" => HttpEntity.Empty
case template => HttpEntity(ContentTypes.`text/html(UTF-8)`, template format uri)
}
您可以引入自己的 RawHeader
而不是 headers.Location(uri)
来构建 Location
header。您可以在您的方案中将实体留空。
(相关文档:https://doc.akka.io//docs/akka-http/current/routing-dsl/directives/route-directives/redirect.html)
我正在使用 Akka Http 为存储在 GCS(Google 云存储)中的文本资源处理签名 url 的重定向。基本上我在 GCS 中有一些文件,我想在请求时与我的 API 一起交付。不幸的是,这个资源的路径有一个子目录,里面有一个 =
字符,比如:https://storage.googleapis.com/path_start/more_path/format=avro/still_more_path/filename.avro
.
Google 存储的 signUrl
方法百分比将此 =
字符编码为签名 url 中的 %3D
。我已经验证使用这个签名 url 允许访问 GCS 中的文件(点击它开始下载)。问题是当 Akka Http 根据请求重定向这个带符号的 url 时,它会将其解码回等号。这会导致 GCS 出现 SignatureDoesNotMatch
错误:
<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>
我尝试生成已签名的 url 并在以下代码片段中重定向它:
val signedUrl = cloudStorageService.getSignedUrl(bucketId, filePath)
logger.info(s"signedUrl: $signedUrl")
redirect(signedUrl, TemporaryRedirect)
和我的cloudStorageService.getSignedUrl
方法在这里单独定义:
def getSignedUrl(bucket: String, path: String, expiration: Option[Int] = None): String = {
val maxLifetime = 60 * 60 * 24 * 7
val lifetime = expiration.getOrElse(maxLifetime)
val cappedExpiration = Math.min(lifetime, maxLifetime)
val blobInfo = BlobInfo.newBuilder(BlobId.of(bucket, path)).build
storage.signUrl(blobInfo, cappedExpiration, TimeUnit.SECONDS, Storage.SignUrlOption.withV4Signature).toString
}
第一个片段中的日志记录语句显示带符号的 URL 是使用 %3D
生成的,但是重定向的 URL 已被百分比解码回 =
,导致 SignatureDoesNotMatch
错误。
此行为是 Akka Http 的标准行为。根据 the documentation for Uri class,所有成员都表示已解码元素的百分比。可以选择使用原始查询字符串构造 uri,但在我的例子中,编码字符出现在 uri 路径本身,而不是查询中。
所以我的问题是,有没有办法让 Akka Http 重定向这个签名的 url 而无需百分比解码路径?还是我弄错了,还有另一种方法可以解决这个问题?
您可能想要创建重定向响应 'manually' 而不是使用 'redirect' 指令。指令实现为:
HttpResponse(
status = redirectionType,
headers = headers.Location(uri) :: Nil,
entity = redirectionType.htmlTemplate match {
case "" => HttpEntity.Empty
case template => HttpEntity(ContentTypes.`text/html(UTF-8)`, template format uri)
}
您可以引入自己的 RawHeader
而不是 headers.Location(uri)
来构建 Location
header。您可以在您的方案中将实体留空。
(相关文档:https://doc.akka.io//docs/akka-http/current/routing-dsl/directives/route-directives/redirect.html)