如何使用Spring WebClient作为文件下载的透传。

huangapple go评论105阅读模式
英文:

How do you use Spring WebClient as a file download passthru

问题

我正在尝试使用WebClient从外部服务下载文件并将其返回给客户端。在Rest Controller中,我有以下的端点:

@GetMapping(value = "/attachment/{fileId}", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public Flux<byte[]> get(@PathVariable String fileId) {

    return this.webClient.get()
            .uri(builder ->
                    builder.scheme("https")
                            .host("external-service.com")
                            .path("/{fileId}")
                            .build(fileId)
            ).attributes(clientRegistrationId("credentials"))
            .accept(MediaType.APPLICATION_OCTET_STREAM)
            .retrieve()
            .bodyToFlux(byte[].class);
}

当我尝试访问该端点时,我得到以下错误:

Exception Class: class org.springframework.http.converter.HttpMessageNotWritableException
Stack Trace: org.springframework.http.converter.HttpMessageNotWritableException: No converter for [class org.springframework.web.servlet.mvc.method.annotation.ReactiveTypeHandler$CollectedValuesList] with preset Content-Type 'null'
	at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:317)
	at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.handleReturnValue(RequestResponseBodyMethodProcessor.java:181)

我尝试返回Flux<DataBuffer>,但仍然收到相同的错误消息。

我正在使用spring-boot-starter-webspring-boot-starter-webflux版本2.2.4.RELEASE。它在一个Tomcat服务器上运行。

我错过了什么吗?

编辑:
我试图将结果以流的方式传输到客户端,而不将整个文件缓冲到内存中。

英文:

I am trying to use WebClient to download a file from a external service and return it to the client. In the Rest Controller, I have the following endpoint:

@GetMapping(value = &quot;/attachment/{fileId}&quot;, produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public Flux&lt;byte[]&gt; get(@PathVariable String fileId) {

    return this.webClient.get()
            .uri(builder -&gt;
                    builder.scheme(&quot;https&quot;)
                            .host(&quot;external-service.com&quot;)
                            .path(&quot;/{fileId}&quot;)
                            .build(fileId)
            ).attributes(clientRegistrationId(&quot;credentials&quot;))
            .accept(MediaType.APPLICATION_OCTET_STREAM)
            .retrieve()
            .bodyToFlux(byte[].class);
}

When I try to hit the endpoint, I get the following error:

Exception Class:class org.springframework.http.converter.HttpMessageNotWritableException
Stack Trace:org.springframework.http.converter.HttpMessageNotWritableException: No converter for [class org.springframework.web.servlet.mvc.method.annotation.ReactiveTypeHandler$CollectedValuesList] with preset Content-Type &#39;null&#39;
	at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:317)
	at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.handleReturnValue(RequestResponseBodyMethodProcessor.java:181)

I have tried returning Flux&lt;DataBuffer&gt; instead, but getting the same error message.

I'm using spring-boot-starter-web and spring-boot-starter-webflux version 2.2.4.RELEASE. It is running on a tomcat server.

What am I missing?

Edit:
I'm trying to stream the result to the client without buffering the whole file into memory.

答案1

得分: 2

这对我来说是可以的。只需将Flux更改为Mono。似乎没有Flux<byte[]>的转换器。

@GetMapping(value = "/attachment/{fileId}", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public Mono<byte[]> get(@PathVariable String fileId) {

    return this.webClient.get()
            .uri(builder ->
                    builder.scheme("https")
                            .host("external-service.com")
                            .path("/{fileId}")
                            .build(fileId)
            ).attributes(clientRegistrationId("credentials"))
            .accept(MediaType.APPLICATION_OCTET_STREAM)
            .retrieve()
            .bodyToMono(byte[].class);
}
英文:

This works for me. Just change from Flux to Mono. Seem there is no converter for Flux<byte[]>

@GetMapping(value = &quot;/attachment/{fileId}&quot;, produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public Mono&lt;byte[]&gt; get(@PathVariable String fileId) {

    return this.webClient.get()
            .uri(builder -&gt;
                    builder.scheme(&quot;https&quot;)
                            .host(&quot;external-service.com&quot;)
                            .path(&quot;/{fileId}&quot;)
                            .build(fileId)
            ).attributes(clientRegistrationId(&quot;credentials&quot;))
            .accept(MediaType.APPLICATION_OCTET_STREAM)
            .retrieve()
            .bodyToMono(byte[].class);
}

huangapple
  • 本文由 发表于 2020年10月27日 06:29:57
  • 转载请务必保留本文链接:https://go.coder-hub.com/64545858.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定