当我从可执行JAR运行SpringBoot应用程序时,下面显示的以下REST端点按预期工作。也就是说,它返回文本"我的测试响应"给客户。但是,当我将相同的应用程序打包为WAR并部署到Tomcat(8.0.29)时,它会引发以下异常:
出现意外错误(type = Internal Server Error,status = 500)。 必须在servlet和异步请求处理中涉及的所有过滤器上启用异步支持。这是使用Servlet API在Java代码中完成的,或者通过添加" true"在web.xml中进行servlet和过滤声明。
package my.rest.controllers;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;
@RestController
@RequestMapping("/api/file")
public class FileContentRestController {
static final int BUFFER = 2048;
@RequestMapping(value = "/content", method = RequestMethod.GET)
@ResponseBody
public StreamingResponseBody getFileContent(HttpServletResponse response) {
response.setContentType("text/plain");
response.setCharacterEncoding("UTF-8");
final InputStream portalFileStream = new ByteArrayInputStream("My test response".getBytes());
return (OutputStream outputStream) -> {
int n;
byte[] buffer = new byte[1024];
while ((n = portalFileStream.read(buffer)) > -1) {
outputStream.write(buffer, 0, n);
}
portalFileStream.close();
};
}
}
我对here和其他地方的理解是,SpringBoot支持SpringBoot注册的所有过滤器和servlet的异步支持。当从具有嵌入式Tomcat容器的独立JAR运行时,情况肯定会出现这种情况。
如何在部署为WAR时确保启用异步支持?
我的SpringBoot应用程序配置如下:
package my;
import com.fasterxml.jackson.core.JsonProcessingException;
import org.springframework.boot.Banner;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;
import org.springframework.scheduling.annotation.EnableAsync;
@SpringBootApplication
@EnableAsync
public class MyRestApp extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return configureApplication(builder);
}
public static void main(String[] args) throws JsonProcessingException {
configureApplication(new SpringApplicationBuilder()).run(args);
}
private static SpringApplicationBuilder configureApplication(SpringApplicationBuilder builder) {
return builder.sources(MyRestApp.class).bannerMode(Banner.Mode.OFF);
}
}
配置了MVC:
package my;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.web.servlet.config.annotation.AsyncSupportConfigurer;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
@Configuration
@EnableWebMvc
@EnableAsync
public class MyMvcConfiguration extends WebMvcConfigurerAdapter {
@Override
public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
configurer.setDefaultTimeout(-1);
configurer.setTaskExecutor(asyncTaskExecutor());
}
@Bean
public AsyncTaskExecutor asyncTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(2);
executor.setMaxPoolSize(2);
executor.setQueueCapacity(500);
executor.setThreadNamePrefix("SpringAsyncThread-");
executor.initialize();
return executor;
}
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedMethods("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS");
}
};
}
}
最后,使用Maven使用以下POM构建和打包应用程序:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.acme</groupId>
<artifactId>my-rest-app</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>my-rest-app</name>
<description></description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>${project.basedir}/src/main/resources</directory>
</resource>
<resource>
<directory>${project.build.directory}/generated-resources</directory>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
答案 0 :(得分:3)
你解析的异常就说明了一切:
出现意外错误(type = Internal Server Error,status = 500)。必须在servlet和异步请求处理中涉及的所有过滤器上启用异步支持。这是使用Servlet API在Java代码中完成的,或者在web.xml中向servlet和过滤器声明添加“true”。
因此,您需要在web.xml中启用它,或者(因为您使用的是spring-boot应用程序),您必须配置特定的bean。
也许这个AppConfig的代码片段会有帮助
@Bean
public ServletRegistrationBean dispatcherServlet() {
ServletRegistrationBean registration = new ServletRegistrationBean(new DispatcherServlet(), "/");
registration.setAsyncSupported(true);
return registration;
}
答案 1 :(得分:1)
我遇到了同样的问题。在嵌入式tomcat服务器(使用maven-tomcat7-plugin)中运行应用程序工作正常,没有错误。部署到外部tomcat服务器(打包为.WAR的spring启动应用程序):
出现意外错误(type = Internal Server Error,status = 500)。必须在servlet和异步请求处理中涉及的所有过滤器上启用异步支持。这是使用Servlet API在Java代码中完成的,或者在web.xml中向servlet和过滤器声明添加“true”。
这是唯一对我有用的解决方案。我必须使用以下内容创建文件src / main / webapp / WEB-INF / web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0" metadata-complete="true">
<filter>
<filter-name>cacheControlFilter</filter-name>
<filter-class>xxx.yourimplementation.CacheControlFilter</filter-class>
<async-supported>true</async-supported>
<init-param>
<param-name>css,html,js</param-name>
<param-value>cache-control=1800,edge-control=1800</param-value>
</init-param>
<init-param>
<param-name>ajax,htm</param-name>
<param-value>cache-control=0,edge-control=0</param-value>
</init-param>
<init-param>
<param-name>doc,gif,ico,jpe,jpeg,jpg,pdf,png,swf</param-name>
<param-value>cache-control=1800,edge-control=7200</param-value>
</init-param>
</filter>
</webapp>
这解决了我的问题。希望它有所帮助!
答案 2 :(得分:1)
我在springboot应用程序中遇到了同样的问题。
Async support must be enabled on a servlet and for all filters involved in async......
我只是添加
@WebFilter(asyncSupported = true)
在我的过滤器中。默认值为false:
/ **
*声明过滤器是否支持异步操作模式。 *
* @see javax.servlet.ServletRequest#startAsync * @see javax.servlet.ServletRequest #startAsync(ServletRequest, * ServletResponse) * /
boolean asyncSupported()默认为false;
答案 3 :(得分:1)
我的外部Tomcat实例是使用NetBeans安装和配置的实例。在%CATALINA_BASE%\ conf文件夹中,有一个web.xml,适用于部署到服务器的所有应用程序。在那里有一个名为HTTPMonitorFilter的过滤器,它不支持异步请求。添加true到该过滤器定义解决了我的问题。
答案 4 :(得分:-1)
使用spring boot SimpleBeanPropertyFilter来解决它
使用下面的链接找到git repo并获得想法
可能有帮助
Git Repo