背景:最近需要在公司老项目里加入Sse实现服务端给客户端推送消息的功能。因为无需双端通信,所以也就选择了Sse没用WebSocket。
Spring和SpringMVC的版本是4.2.4.RELEASE,JDK为1.7,tomcat为7.0.90。
<spring.version>4.2.4.RELEASE</spring.version>
...
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
这是Controller的连接接口。
@RequestMapping("/connect")
public SseEmitter connect() {
//默认是30s超时,设置为0L永不超时
SseEmitter sseEmitter = new SseEmitter(0L);
// ...
return sseEmitter;
}
发起请求后,后端正常返回SseEmitter无报错,但前端却一直连接不上(使用Apifox进行测试)。
把连接接口直接复制,放到SpringBoot中,直接请求就连接成功。(因为SpringBoot自动开启了异步支持)
在网上搜SSE、SseEmitter,都只是写着如何使用,没有说配置相关的。(还是对SpringMVC不了解导致的)
后面实在解决不了,换成DeferredResult使用,直接报错提示Request processing failed; nested exception is java.lang.IllegalStateException: Async support must be enabled on a servlet and for all filters involved in async request processing. This is done in Java code using the Servlet API or by adding "<async-supported>true</async-supported>" to servlet and filter declarations in web.xml.
。(需要把web.xml中的<error-code>500</error-code>
注释掉才能看到)
到这里,才知道web.xml里没开启对异步的支持。对web.xml中的<servlet>
、<filter>
、<filter-mapping>
都加上对异步的支持。(多个filter最好都加上)
<async-supported>true</async-supported>
<dispatcher>ASYNC</dispatcher>
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
<async-supported>true</async-supported>
</servlet>
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<async-supported>true</async-supported>
<init-param>
<param-name>encoding</param-name>
<param-value>utf8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>ASYNC</dispatcher>
</filter-mapping>
...
重启后,DeferredResult可以成功连接了,换成SseEmitter也可以重新连接了。(记得把<error-code>500</error-code>
注释去掉)
Sse的使用可以看看这篇文章:https://juejin.cn/post/7373669988388339723?searchId=202406241455318222F3C07D510A2B8FED