英文:
How to use scala sttp client to download file
问题
我有任务要检查AWS定价,它是一个公共的JSON文件,不需要认证。
我使用了Tapir Sttp库。
val request: Request[Either[String, String], Any] = basicRequest
.header(HeaderNames.Accept, MediaType.ApplicationOctetStream.toString())
.get(uri"https://pricing.us-east-1.amazonaws.com/offers/v1.0/aws/index.json")
val response = request.send(sttpBackend)
val res = Await.result(response, 30.seconds)
以上是我的简单GET请求。
但是我遇到了错误:
导致: java.io.UnsupportedEncodingException: 不支持的编码
我可以从浏览器下载文件,从Postman获取JSON。
有人知道如何使用sttp客户端下载文件吗?
谢谢
尝试从Amazon定价终端点下载JSON文件。
英文:
I have task to check AWS pricing, it's a public json file. there is no auth needed.
I use Tapir Sttp library
val request: Request[Either[String, String], Any] = basicRequest
.header(HeaderNames.Accept, MediaType.ApplicationOctetStream.toString())
.get(uri"https://pricing.us-east-1.amazonaws.com/offers/v1.0/aws/index.json")
val response = request.send(sttpBackend)
val res = Await.result(response, 30.seconds)
above is my simple get call.
But I got error
Caused by: java.io.UnsupportedEncodingException: Unsupported encoding
I can download the file from browers, get the json from Postman.
Anybody know how to download file by sttp client
Thanks
try to download json file from amazon pricing endpoint
答案1
得分: 4
代码部分不需要翻译。以下是翻译好的部分:
看起来 AWS 终端点返回了一个带有空的 Content-Encoding
头的响应:
> GET /offers/v1.0/aws/index.json HTTP/1.1
> Host: pricing.us-east-1.amazonaws.com
> User-Agent: curl/7.88.1
> Accept: */*
<
< HTTP/1.1 200 OK
< Content-Type: application/octet-stream
(...)
< x-amz-server-side-encryption: AES256
< Content-Encoding:
< x-amz-version-id: RPn8P8KKFZDsbbPZSHSPEAxgOPJ4okmH
(...)
我们的代码试图将一个支持的解码算法与头的值进行匹配,如果存在的话。这会失败,因为空字符串没有解码算法。
我已经创建了一个问题来在 sttp 中修复这个问题。修复方法是忽略头的空值。
还有一个解决方法:你可以提供一个自定义的编码处理程序来“处理”空值。例如,使用 HttpURLConnectionBackend
:
object Test extends App {
val request: Request[Either[String, String], Any] = basicRequest
.header(HeaderNames.Accept, MediaType.ApplicationOctetStream.toString())
.get(uri"https://pricing.us-east-1.amazonaws.com/offers/v1.0/aws/index.json")
val backend = HttpURLConnectionBackend(customEncodingHandler = { case (is, "") => is })
println(request.send(backend))
}
英文:
It seems the aws endpoint returns a response with an empty Content-Encoding
header:
> GET /offers/v1.0/aws/index.json HTTP/1.1
> Host: pricing.us-east-1.amazonaws.com
> User-Agent: curl/7.88.1
> Accept: */*
>
< HTTP/1.1 200 OK
< Content-Type: application/octet-stream
(...)
< x-amz-server-side-encryption: AES256
< Content-Encoding:
< x-amz-version-id: RPn8P8KKFZDsbbPZSHSPEAxgOPJ4okmH
(...)
Our code tries to match one of the supported decoding algorithms to the value of the header, if it is present. This fails, as there is no algorithm for an empty string.
I've created an issue to fix that in sttp. The fix is to ignore empty values of the header.
There is also a work-around: you can provide a custom encoding handler to "handle" the empty value. For example, using the HttpURLConnectionBackend
:
object Test extends App {
val request: Request[Either[String, String], Any] = basicRequest
.header(HeaderNames.Accept, MediaType.ApplicationOctetStream.toString())
.get(uri"https://pricing.us-east-1.amazonaws.com/offers/v1.0/aws/index.json")
val backend = HttpURLConnectionBackend(customEncodingHandler = { case (is, "") => is })
println(request.send(backend))
}
答案2
得分: 0
我实际上在上述提到的URL上尝试了curl
,Content-Encoding:
部分为空。
并且 sttp.client3.HttpClientSyncBackend.standardEncoding
因为空的 Content-Encoding
而失败:https://github.com/softwaremill/sttp/blob/v3.8.15/core/src/main/scalajvm/sttp/client3/HttpClientSyncBackend.scala#LL64C16-L64C16
因此,您需要绕过 standardEncoding
并创建一个具有自定义编码的后端,以处理空的 Content-Encoding
标头,方法是提供一个简单的自定义编码处理程序 (customEncodingHandler: [(InputStream, String) => InputStream] = (is, _) => is
)
val backend = HttpClientSyncBackend(customEncodingHandler = (is, _) => is)
// 创建您的请求
val request = ???
val response = request.send(backend)
val res = Await.result(response, 30.seconds)
英文:
I actually tried curl
on the above mentioned URL, the Content-Encoding:
is coming as empty.
curl -X GET https://pricing.us-east-1.amazonaws.com/offers/v1.0/aws/index.json --output ~/Desktop/pricing-index.json -v
Note: Unnecessary use of -X or --request, GET is already inferred.
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0* Trying 54.192.150.79:443...
* Connected to pricing.us-east-1.amazonaws.com (54.192.150.79) port 443 (#0)
* ALPN: offers h2
* ALPN: offers http/1.1
## <-- redacted -->
> GET /offers/v1.0/aws/index.json HTTP/1.1
> Host: pricing.us-east-1.amazonaws.com
> User-Agent: curl/7.87.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Content-Type: application/octet-stream
< Content-Length: 69431
< Connection: keep-alive
< Date: Tue, 13 Jun 2023 06:29:27 GMT
< Last-Modified: Tue, 13 Jun 2023 01:42:43 GMT
< x-amz-server-side-encryption: AES256
< Content-Encoding:
## <-- redacted -->
<
{ [1455 bytes data]
100 69431 100 69431 0 0 41107 0 0:00:01 0:00:01 --:--:-- 41229
* Connection #0 to host pricing.us-east-1.amazonaws.com left intact
And the sttp.client3.HttpClientSyncBackend.standardEncoding
is failing due to empty Content-Encoding : https://github.com/softwaremill/sttp/blob/v3.8.15/core/src/main/scalajvm/sttp/client3/HttpClientSyncBackend.scala#LL64C16-L64C16
So, you need to bypass the standardEncoding
and create a backend with custom encoding to handle the empty Content-Encoding header by providing just a pass-through customEncodingHandler ( customEncodingHandler: [(InputStream, String) => InputStream] = (is, _) => is
)
I
val backend = HttpClientSyncBackend(customEncodingHandler = (is, _) => is)
// create your request
val request = ???
val response = request.send(backend)
val res = Await.result(response, 30.seconds)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论