我正在尝试在控制器中使用返回类型Callable,以便在处理请求时释放servlet线程,但是当在开发环境中部署spring boot应用程序时,我收到以下错误:
org.springframework.web.util.NestedServletException:Request 处理失败;嵌套异常是 java.lang.IllegalStateException:必须在a上启用异步支持 servlet和异步请求处理中涉及的所有过滤器。这个 使用Servlet API或通过添加在Java代码中完成 对servlet和过滤器的“真实” web.xml中的声明。
注意:我已经阅读了几篇关于此错误的帖子,但没有一个解决了我的问题。
我所拥有的特定行为是本地一切都按预期工作:释放servlet线程并且带外处理请求以最终返回到客户端所需的响应。
但是,如前所述,当应用程序部署在开发环境中时,事情就无法正常工作。
在本地测试时,我检查了servlet / filters是否支持异步;调试时要做的只是在ApplicationFilterChain
的给定过滤器中放置一个断点,然后检查整个链。在那里,我可以检查servlet属性(我在其中看到asyncSupported为true)以及链中包含的每个过滤器(我逐个检查它们;所有这些都设置为asyncSupported为true)。
我还有一个自定义JwtAuthenticationFilter
,它作为身份验证阶段的一部分从AbstractAuthenticationProcessingFilter
延伸,所以我也在这样的过滤器中放置一个断点并检查链。在那里,我看到原始链接(前面注释为ApplicationFilterChain
)和“additionalFilters”集合,其中出现了JwtAuthenticationFilter
以及spring安全过滤器。但是它们都没有asyncSupported属性,所以我假设它们不是开发服务器抛出的错误的一部分。请注意,正如我在本地提到的,一切正常;部署到开发服务器时出现错误。
控制器方法:
@GetMapping(path = "/export")
public Callable<ResponseEntity> exportData() throws IOException {
return new CustomContextAwareCallable(() -> handleResponse());
}
所以我的问题是:即使ApplicationFilterChain上的每个过滤器和servlet都有asyncSupported为true,为什么我在部署后会从服务器收到上面显示的错误?
应用程序未在服务器上部署为.WAR,它只是使用嵌入式tomcat(我在本地做同样的事情)。
更新:另一个不同之处在于,在开发环境中,客户端请求通过nginx代理(只是想知道是否由于某种原因,请求属性org.apache.catalina.ASYNC_SUPPORTED
可能被修改为假(本地它是真的)。
有什么想法吗?
答案 0 :(得分:1)
我通过向当前请求添加async支持属性找到了一种解决方法,如:
@GetMapping(path = "/export")
public Callable<ResponseEntity> exportData(HttpServletRequest request) throws IOException {
request.setAttribute(org.apache.catalina.Globals.ASYNC_SUPPORTED_ATTR, true);
return new CustomContextAwareCallable(() -> handleResponse());
}
由于所有过滤器都与dispatchServlet一起被异步支持,因此使用(如原始问题所述)似乎在开发环境中部署时,以下某些tomcat阀门为请求设置了false属性:
我在本地验证了嵌入式tomcat版本,它与开发环境相同:Apache Tomcat/8.5.23
似乎我之前显示的错误:
org.springframework.web.util.NestedServletException:Request 处理失败;嵌套异常是 java.lang.IllegalStateException:必须在a上启用异步支持 servlet和异步请求处理中涉及的所有过滤器。这个 使用Servlet API在Java代码中完成,或者添加\&#34; true \&#34;至 web.xml中的servlet和过滤器声明。
并不完全依赖于servlet&amp;如上所述过滤器,因为任何列出的tomcat阀门最终都可能不允许请求异步支持。
目前我还没有足够的细节知道为什么会发生这种情况(如果有机会针对开发环境进行远程调试,看看每个tomcat阀门是如何处理的话会很棒请求)。
答案 1 :(得分:0)
对于具有Filter
实现的用户。您可以在request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR, true)
回调中执行相同的操作,而不是为Controller
中的每个请求设置doFilter()
。这就是我在Kotlin中所做的事情:
import org.apache.catalina.Globals
import javax.servlet.Filter
import javax.servlet.FilterChain
import javax.servlet.ServletRequest
import javax.servlet.ServletResponse
import javax.servlet.annotation.WebFilter
import javax.servlet.http.HttpServletResponse
@Suppress("unused")
@WebFilter(urlPatterns = ["/v1/*"])
class RequestResponseFilter : Filter {
override fun doFilter(request: ServletRequest, response: ServletResponse, chain: FilterChain) {
request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR, true)
val httpServletResponse = response as HttpServletResponse
httpServletResponse.setHeader("Cache-Control", "max-age=60")
chain.doFilter(request, response)
}
}