响应式Spring在REST端点中不支持将HttpServletRequest作为参数?

32

我创建了一个Rest控制器,代码如下:

@RestController
public class GreetingController {

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

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

很遗憾,当我尝试访问“greetings”端点时,出现了异常:

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

我正在使用:

compile('org.springframework.boot.experimental:spring-boot-starter-web-reactive')
如何解决这个问题?
完整的堆栈跟踪链接:Link,build.gradle链接:Link ----------编辑---------- 现在使用接口。 现在出现以下错误:

java.lang.IllegalStateException: No resolver for argument [0] of type [javax.servlet.http.HttpServletRequest] on method (rest is same)


1
您正在使用错误的 HttpServletRequest。请使用接口而不是具体实现。 - M. Deinum
已经修复了,但是Spring仍然有问题。 - Dexter
尝试在 HttpServletRequest request 前面添加 @Context?http://cxf.apache.org/docs/jax-rs-basics.html#JAX-RSBasics-Contextannotations - Lawrence Tierney
没有一个像我在回答中提到的"HandlerMethodArgumentResolver"处理这个注释。我认为ServletServerHttpRequest是正确的选择... - Dexter
2个回答

50

在Spring Reactive Web应用程序中,永远不要使用Servlet API。这是不被支持的,并且会导致您的应用程序依赖于容器,而Spring Web Reactive可以与非Servlet运行时(如Netty)一起使用。

相反,您应该使用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


我可以理解“使您的应用程序依赖于容器”,但是“不支持”是什么意思? - Dexter
3
您使用的用于获取servlet响应的类是内部类,不应在应用程序代码中使用。这也可能会带来很多问题,因为您只应使用Servlet 3.1异步IO API来写入正文,否则您将面临完全阻塞应用程序的风险。 - Brian Clozel

4

我深入了解了调用层次结构,并发现有这个类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 包。


1
这个类不再是公共的了。它以前是公共的吗? - mdzh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接