Reactive Spring 不支持 HttpServletRequest 作为 REST 端点中的参数?

Posted

技术标签:

【中文标题】Reactive Spring 不支持 HttpServletRequest 作为 REST 端点中的参数?【英文标题】:Reactive Spring does not support HttpServletRequest as parameter in REST endpoint? 【发布时间】:2017-03-14 15:57:08 【问题描述】:

我创建了一个如下所示的 RestController:

@RestController
public class GreetingController 

    @RequestMapping(value = "/greetings", method = RequestMethod.GET)
    public Mono<Greeting> greeting(HttpServletRequest request) 

        return Mono.just(new Greeting("Hello..." + request.toString()));
    

不幸的是,当我尝试点击“问候”端点时,我得到了一个异常:

java.lang.IllegalStateException:没有类型的参数 [0] 的解析器 [org.apache.catalina.servlet4preview.http.HttpServletRequest]

我正在使用

compile('org.springframework.boot.experimental:spring-boot-starter-web-reactive')

如何解决这个问题?

Link 到完整的堆栈跟踪。 Link build.gradle

---------编辑---------

使用界面。现在得到:

java.lang.IllegalStateException:没有类型的参数 [0] 的解析器 [javax.servlet.http.HttpServletRequest] on 方法(其余相同)

【问题讨论】:

您使用了错误的HttpServletRequest。使用接口而不是具体的实现。 已修复,但 Spring 仍然给您带来麻烦。 尝试在 HttpServletRequest 请求之前添加@Context? cxf.apache.org/docs/… Nope 没有一个“HandlerMethodArgumentResolver”,如下面我的回答中提到的那样处理这个注释。我认为 ServletServerHttpRequest 是要走的路... 【参考方案1】:

您应该从不在 Spring Reactive Web 应用程序中使用 Servlet API。这不受支持,这会使您的应用程序依赖于容器,而 Spring Web Reactive 可以与 Netty 等非 Servlet 运行时一起使用。

您应该使用 Spring 提供的 HTTP API;这是您的代码示例,有一些更改:

import org.springframework.http.server.reactive.ServletServerHttpRequest;

@RestController
public class GreetingController 

    @GetMapping("/greetings")
    public Mono<Greeting> greeting(ServerHttpRequest request) 

        return Mono.just(new Greeting("Hello..." + request.getURI().toString()));
    

您可以注入ServerWebExchange 或直接注入ServerHttpRequest / ServerHttpResponse

【讨论】:

我可以理解“使您的应用程序依赖于容器”,但是“不支持”是什么意思? 您用来获取 servlet 响应的类是内部的,不应在应用程序代码中使用。这也可能会带来很大的问题,因为您应该只使用 Servlet 3.1 异步 IO API 来写入主体,否则您将面临完全阻塞您的应用程序的风险。【参考方案2】:

深入调用层次结构,发现有这个类 InvocableHandlerMethod,在 org.springframework.web.reactive.result.method 包中 ,其中有:

private List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>();

这个类中有一个resolveArguments()方法,被调用来“解析参数”。不幸的是,没有解析器 javax.servlet.http.HttpServletRequest 在此列表中。

但是有一个 ServerWebExchangeArgumentResolver 能够解析 ServletServerHttpRequest,我可以从中提取 HttpServletRequest。是啊……

所以端点看起来像:

@RequestMapping(value = "/greetings", method = RequestMethod.GET)
public Mono<Greeting> greeting(ServletServerHttpRequest servletServerHttpRequest) 

    HttpServletRequest httpServletRequest = servletServerHttpRequest.getServletRequest();
    .
    .
    .

重要的是 ServletServerHttpRequest 来自包 org.springframework.http.server.reactive

【讨论】:

该课程不再公开。过去是公开的吗?

以上是关于Reactive Spring 不支持 HttpServletRequest 作为 REST 端点中的参数?的主要内容,如果未能解决你的问题,请参考以下文章

Reactive Spring 不支持 HttpServletRequest 作为 REST 端点中的参数?

Spring WebFlux Reactive 和 Kotlin Coroutines 启动错误

Spring Boot Reactive Streams

Spring 5:使用 Spring Webflux 开发 Reactive 应用

Spring容器类型推断

Spring WebClient 放置映射:不支持内容类型“application/json”