如何使用 ktor 客户端设置 HttpServletResponse 的主体

Posted

技术标签:

【中文标题】如何使用 ktor 客户端设置 HttpServletResponse 的主体【英文标题】:How to set body of HttpServletResponse using ktor client 【发布时间】:2019-11-10 16:59:29 【问题描述】:

我有弹簧启动控制器

@PostMapping(path = ["/download"])
fun getFile(@RequestBody myObjectRq: myObjectRq, httpServletResponse: HttpServletResponse): CompletableFuture<HttpServletResponse> 
    return GlobalScope.async 
       val response = webService.getFile(myObjectRq)
       response?.let 
           httpServletResponse.setHeader("Content-Type", response.headers.get("Content-Type"))
           httpServletResponse.setHeader("Content-Disposition", response.headers.get("Content-Disposition"))
           httpServletResponse.writer.write(String(response.content.toByteArray()))
           httpServletResponse.writer.flush()
           httpServletResponse.status = response.status.value
       
       httpServletResponse
   .asCompletableFuture()

在其中我使用服务,该服务又使用 ktor 客户端向外部服务器发送发布请求,外部服务器应该响应发送 csv 文件。 csv 文件内容取决于我在myObjectRq 中发送的值。

服务:

suspend fun getFile(myObjectRq: myObjectRq): HttpResponse 
    val response = ktorClient.post<HttpResponse> 
        accept(ContentType.Application.OctetStream)
        url(externalWebServerUrl)
        body = myObjectRq
        contentType(ContentType.Application.Json)
    
    log.info(String(response.content.toByteArray()))
    response

响应的标题设置正确,方法中的log.info(String(response.content.toByteArray()))也打印出接收文件的内容,但我不能将其设置为HttpServletResponse的正文。我不断收到org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation

我还得到了Inappropriate blocking method callhttpServletResponse.writer,这会破坏ktor 客户端的异步特性。 我做错了什么?我该如何解决?

【问题讨论】:

【参考方案1】:

所以,我认为 SpringBoot 与您的返回类型混淆了。它试图找到一种方法将您的返回 CompletableFuture&lt;HttpServletResponse&gt; 序列化到 HTTP 响应的正文中,但失败了。我相信您可以通过如下更改实现来获得相同的结果:

@PostMapping(path = ["/download"])
fun getFile(@RequestBody myObjectRq: myObjectRq, httpServletResponse: HttpServletResponse): CompletableFuture<Void> 
    return GlobalScope.async 
       val response = webService.getFile(myObjectRq)
       response?.let 
           httpServletResponse.setHeader("Content-Type", response.headers.get("Content-Type"))
           httpServletResponse.setHeader("Content-Disposition", response.headers.get("Content-Disposition"))
           httpServletResponse.writer.write(String(response.content.toByteArray()))
           httpServletResponse.writer.flush()
           httpServletResponse.status = response.status.value
       
       null
   .asCompletableFuture()

【讨论】:

我实际上尝试过使用 Unit,这还不错,因为响应中已打印出正文,但仍然存在弹簧错误。【参考方案2】:

我实际上设法使用CompletableFuture&lt;ResponseEntity&lt;ByteArray&gt;&gt; 作为返回类型并以这种方式设置响应主体来解决这个问题: ResponseEntity.ok().body(response.content.toByteArray()) 这也删除了Inappropriate blocking method call 警告。

【讨论】:

以上是关于如何使用 ktor 客户端设置 HttpServletResponse 的主体的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 ktor 获取客户端 IP

如何使用 okhttp 引擎将 HostnameVerifier 添加到 ktor 客户端

控制Ktor 0.9.0 servlet中的cookie生命周期

使用 Ktor 部署:如何设置 AppEngine 版本?

如何使用 ktor 解析 HTTP 标头

如何在 IntelliJ IDEA 中为 Ktor 设置运行配置?