mel*_*ros 7 java spring spring-mvc spring-boot
我正在尝试像这篇文章中那样使用 Springs SseEmitter: Angular 2 spring boot server side events。推送事件正在运行,但每次我关闭或刷新选项卡时,我都会遇到以下异常。
奇怪的是,异常是在发射器的 send方法中抛出的,该方法被 try catch 块包围。必须在方法中捕获并记录并重新抛出异常。但是我怎么能阻止它。我不想抑制错误日志。
IOException: Eine bestehende Verbindung wurde softwaregesteuert durch den Hostcomputer abgebrochen
IOEexception an established connection was aborted by the software in your host machine
Run Code Online (Sandbox Code Playgroud)
谢谢!
控制器.java
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@RestController
public class SSEController {
public static final List<SseEmitter> emitters = Collections.synchronizedList( new ArrayList<>());
@RequestMapping(path = "/stream", method = RequestMethod.GET)
public SseEmitter stream() throws IOException {
SseEmitter emitter = new SseEmitter();
emitters.add(emitter);
emitter.onCompletion(() -> emitters.remove(emitter));
return emitter;
}
}
Run Code Online (Sandbox Code Playgroud)
服务类.java
@Scheduled
public void sendSseEventsToUI(Notification notification) { //your model class
List<SseEmitter> sseEmitterListToRemove = new ArrayList<>();
SSEController.emitters.forEach((SseEmitter emitter) -> {
try {
emitter.send(notification, MediaType.APPLICATION_JSON);
} catch (Exception e) {
emitter.complete();
sseEmitterListToRemove.add(emitter);
}
});
SSEController.emitters.removeAll(sseEmitterListToRemove);
}
Run Code Online (Sandbox Code Playgroud)
例外:
> 2017-12-27 13:54:53.206 INFO 4248 --- [pool-4-thread-1]
> o.apache.coyote.http11.Http11Processor : An error occurred in
> processing while on a non-container thread. The connection will be
> closed immediately
>
> java.io.IOException: Eine bestehende Verbindung wurde
> softwaregesteuert durch den Hostcomputer abgebrochen at
> sun.nio.ch.SocketDispatcher.write0(Native Method) ~[na:1.8.0_121] at
> sun.nio.ch.SocketDispatcher.write(SocketDispatcher.java:51)
> ~[na:1.8.0_121] at
> sun.nio.ch.IOUtil.writeFromNativeBuffer(IOUtil.java:93)
> ~[na:1.8.0_121] at sun.nio.ch.IOUtil.write(IOUtil.java:65)
> ~[na:1.8.0_121] at
> sun.nio.ch.SocketChannelImpl.write(SocketChannelImpl.java:471)
> ~[na:1.8.0_121] at
> org.apache.tomcat.util.net.NioChannel.write(NioChannel.java:134)
> ~[tomcat-embed-core-8.5.23.jar:8.5.23] at
> org.apache.tomcat.util.net.NioBlockingSelector.write(NioBlockingSelector.java:101)
> ~[tomcat-embed-core-8.5.23.jar:8.5.23] at
> org.apache.tomcat.util.net.NioSelectorPool.write(NioSelectorPool.java:157)
> ~[tomcat-embed-core-8.5.23.jar:8.5.23] at
> org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper.doWrite(NioEndpoint.java:1267)
> ~[tomcat-embed-core-8.5.23.jar:8.5.23] at
> org.apache.tomcat.util.net.SocketWrapperBase.doWrite(SocketWrapperBase.java:670)
> ~[tomcat-embed-core-8.5.23.jar:8.5.23] at
> org.apache.tomcat.util.net.SocketWrapperBase.flushBlocking(SocketWrapperBase.java:607)
> ~[tomcat-embed-core-8.5.23.jar:8.5.23] at
> org.apache.tomcat.util.net.SocketWrapperBase.flush(SocketWrapperBase.java:597)
> ~[tomcat-embed-core-8.5.23.jar:8.5.23] at
> org.apache.coyote.http11.Http11OutputBuffer.flushBuffer(Http11OutputBuffer.java:581)
> ~[tomcat-embed-core-8.5.23.jar:8.5.23] at
> org.apache.coyote.http11.Http11OutputBuffer.flush(Http11OutputBuffer.java:272)
> ~[tomcat-embed-core-8.5.23.jar:8.5.23] at
> org.apache.coyote.http11.Http11Processor.flush(Http11Processor.java:1560)
> ~[tomcat-embed-core-8.5.23.jar:8.5.23] at
> org.apache.coyote.AbstractProcessor.action(AbstractProcessor.java:283)
> ~[tomcat-embed-core-8.5.23.jar:8.5.23] at
> org.apache.coyote.Response.action(Response.java:173)
> [tomcat-embed-core-8.5.23.jar:8.5.23] at
> org.apache.catalina.connector.OutputBuffer.doFlush(OutputBuffer.java:317)
> [tomcat-embed-core-8.5.23.jar:8.5.23] at
> org.apache.catalina.connector.OutputBuffer.flush(OutputBuffer.java:284)
> [tomcat-embed-core-8.5.23.jar:8.5.23] at
> org.apache.catalina.connector.CoyoteOutputStream.flush(CoyoteOutputStream.java:118)
> [tomcat-embed-core-8.5.23.jar:8.5.23] at
> sun.nio.cs.StreamEncoder.implFlush(StreamEncoder.java:297)
> [na:1.8.0_121] at
> sun.nio.cs.StreamEncoder.flush(StreamEncoder.java:141) [na:1.8.0_121]
> at java.io.OutputStreamWriter.flush(OutputStreamWriter.java:229)
> [na:1.8.0_121] at
> org.springframework.util.StreamUtils.copy(StreamUtils.java:119)
> [spring-core-4.3.13.RELEASE.jar:4.3.13.RELEASE] at
> org.springframework.http.converter.StringHttpMessageConverter.writeInternal(StringHttpMessageConverter.java:106)
> [spring-web-4.3.13.RELEASE.jar:4.3.13.RELEASE] at
> org.springframework.http.converter.StringHttpMessageConverter.writeInternal(StringHttpMessageConverter.java:41)
> [spring-web-4.3.13.RELEASE.jar:4.3.13.RELEASE] at
> org.springframework.http.converter.AbstractHttpMessageConverter.write(AbstractHttpMessageConverter.java:227)
> [spring-web-4.3.13.RELEASE.jar:4.3.13.RELEASE] at
> org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitterReturnValueHandler$HttpMessageConvertingHandler.sendInternal(ResponseBodyEmitterReturnValueHandler.java:207)
> [spring-webmvc-4.3.13.RELEASE.jar:4.3.13.RELEASE] at
> org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitterReturnValueHandler$HttpMessageConvertingHandler.send(ResponseBodyEmitterReturnValueHandler.java:200)
> [spring-webmvc-4.3.13.RELEASE.jar:4.3.13.RELEASE] at
> org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitter.sendInternal(ResponseBodyEmitter.java:166)
> [spring-webmvc-4.3.13.RELEASE.jar:4.3.13.RELEASE] at
> org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitter.send(ResponseBodyEmitter.java:159)
> [spring-webmvc-4.3.13.RELEASE.jar:4.3.13.RELEASE] at
> org.springframework.web.servlet.mvc.method.annotation.SseEmitter.send(SseEmitter.java:126)
> [spring-webmvc-4.3.13.RELEASE.jar:4.3.13.RELEASE] at
> org.springframework.web.servlet.mvc.method.annotation.SseEmitter.send(SseEmitter.java:107)
> [spring-webmvc-4.3.13.RELEASE.jar:4.3.13.RELEASE] at
> com.example.demo.PushService.sendSseEventsToUI(PushService.java:22)
> [classes/:na] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native
> Method) ~[na:1.8.0_121] at
> sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
> ~[na:1.8.0_121] at
> sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
> ~[na:1.8.0_121] at java.lang.reflect.Method.invoke(Method.java:498)
> ~[na:1.8.0_121] at
> org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:65)
> [spring-context-4.3.13.RELEASE.jar:4.3.13.RELEASE] at
> org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54)
> [spring-context-4.3.13.RELEASE.jar:4.3.13.RELEASE] at
> java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
> [na:1.8.0_121] at
> java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308)
> [na:1.8.0_121] at
> java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180)
> [na:1.8.0_121] at
> java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294)
> [na:1.8.0_121] at
> java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
> [na:1.8.0_121] at
> java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
> [na:1.8.0_121] at java.lang.Thread.run(Thread.java:745)
> [na:1.8.0_121]
Run Code Online (Sandbox Code Playgroud)
您正在看到来自 org.apache.coyote.http11.Http11Processor 的日志。您之所以得到它,是因为 servlet api 在客户端连接关闭时不通知。这就是为什么它无论如何都会尝试在套接字上写入的原因,更多信息请访问jira.spring.io/browse/SPR-13292
如果您不想看到此日志,请通过添加此属性(在 application.properties 中)更改此包的日志级别:
logging.level.org.apache.coyote.http11=ERROR
Run Code Online (Sandbox Code Playgroud)
或者您可以编辑记录器配置文件。
此外,不要使用静态最终集合来保持发射器执行以下操作:
为您服务
private final Collection<SseEmitter> emitters = Collections.synchronizedCollection(new HashSet<SseEmitter>());
public void register(SseEmitter emitter) {
emitter.onTimeout(() -> timeout(emitter));
emitter.onCompletion(() -> complete(emitter));
emitters.add(emitter);
}
private void complete(SseEmitter emitter) {
System.out.println("emitter completed");
emitters.remove(emitter);
}
private void timeout(SseEmitter emitter) {
System.out.println("emitter timeout");
emitters.remove(emitter);
}
@Scheduled(fixedDelay = 3000)
public void sendSseEventsToUI() { //your model class
for(SseEmitter emitter : emitters) {
try {
emitter.send(UUID.randomUUID().toString(), MediaType.APPLICATION_JSON);
} catch (Throwable e) {
emitter.complete();
}
};
}
Run Code Online (Sandbox Code Playgroud)
在您的控制器中:
@Autowired
public PushController(PushService service) {
this.service = service;
}
@RequestMapping(path = "/", method = RequestMethod.GET)
public SseEmitter stream() {
final SseEmitter emitter = new SseEmitter(0L);
service.register(emitter);
return emitter;
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3849 次 |
| 最近记录: |