Closed FPEsocrter closed 2 months ago
AsyncContextImpl AsyncContextImpl.complete is not called
@FPEsocrter sorry but the description is not actionable. I am not sure if you're trying to report a bug or a request for enhancement. Can you please edit the original description and provide more details?
@Component
public class ComputingPowerCheckerInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
System.out.println("preHandle");
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
System.out.println("afterCompletion");
}
}
package cn.biz;
import jakarta.servlet.AsyncContext;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.RequestFacade;
import org.apache.coyote.ActionCode;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import java.io.PrintWriter;
import java.lang.reflect.Field;
import java.util.Map;
@RestController
@RequestMapping("/language")
public class LanguageController {
@GetMapping("/open")
public Map<String, Object> open() {
return Map.of("", "");
}
@GetMapping("/see")
public SseEmitter See(HttpServletRequest request ) throws Exception {
System.out.println("see");
SseEmitter sseEmitter = new SseEmitter();
new Thread(() -> {
try {
sseEmitter.send("tes", MediaType.TEXT_PLAIN);
Thread.sleep(3*1000);
sseEmitter.send("tes", MediaType.TEXT_PLAIN);
sseEmitter.complete();
} catch (Exception e) {
throw new RuntimeException(e);
}
}).start();
return sseEmitter;
}
@GetMapping("/response")
public void testResp(ServletRequest request, ServletResponse response){
AsyncContext asyncContext = request.startAsync();
System.out.println("response");
asyncContext.start(() -> {
try {
PrintWriter out = asyncContext.getResponse().getWriter();
out.println("test");
out.flush();
Thread.sleep(3*1000);
out.println("test");
out.flush();
out.close();
asyncContext.complete();
} catch (Exception e) {
throw new RuntimeException(e);
}
});
}
}
transfer /response preHandle one
response Print Order
preHandle
response
afterCompletion
transfer / see preHandle twice
see Print Order
preHandle
see
afterCompletion
preHandle
Normally it should only be called once preHandle
sseEmitter.complete(); AsyncContextImpl.complete is not called. is bug
Sorry but dumping code in text like that is not very helpful. Someone might see what the problem could be, but I don't. If you want to speed up support, please move all that code into an actual small application we can run ourselves. You can attach a zip to this issue or push the code to a GitHub repository.
Generally Spring MVC executes async requests in two phases as described in the docs. The first covers controller method invocation and async handling. After that we perform an ASYNC dispatch to complete processing on a Servlet container thread, which is required in some cases like view rendering.
The same is true for the SseEmitter scenario as well, in which case it looks a bit more strange because there is no further handling once the stream is over, but it provides consistency in the Spring MVC request lifecycle (exception handling, interception, etc).
If you want to ignore the second preHandle you can check if request.getDispatcherType()
is ASYNC.
HandlerInterceptor Interception SseEmitter Mapping Multiple execution preHandle
AsyncContextImpl AsyncContextImpl.complete is not called