【问题标题】:HttpMediaTypeNotAcceptableException: Could not find acceptable representation - MediaType produces different resultsHttpMediaTypeNotAcceptableException:找不到可接受的表示 - MediaType 产生不同的结果
【发布时间】:2020-09-04 15:37:32
【问题描述】:

使用 Spring MVC,我有一个控制器,其端点返回 SseEmitter。

@GetMapping(path = "/accept/{amount}", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    @ApiResponses({
            @ApiResponse(responseCode = "200", description = "OK"),
            @ApiResponse(responseCode = "409", description = "BUSY", content = @Content(schema = @Schema(implementation = MyErrorClass.class))),
            @ApiResponse(responseCode = "500", description = "UNEXPECTED_ERROR", content = @Content(schema = @Schema(implementation = MyErrorClass.class)))
    })
    public SseEmitter accept(@Parameter(description = "Amount to accept") @PathVariable double amount) throws MyException {
        ExecutorService service = Executors.newCachedThreadPool();
        SseEmitter emitter = new SseEmitter();
        myService.accept(amount);
        service.execute(() -> {
            while(myService.inAcceptanceState()) {
                try {
                    emitter.send(myService.getCurrentAmount());
                    Thread.sleep(1000);
                } catch (InterruptedException | IOException ex) {
                    emitter.completeWithError(ex);
                }
            }
            try {
                emitter.send(myService.getCurrentAmount());
                emitter.complete();
            } catch (IOException e) {
                emitter.completeWithError(e);
            }
        });
        service.shutdown();
        return emitter;
    }

在上述代码的情况下,accept() 方法在第一次调用完成之前第二次调用时预计会抛出 400 错误。截至目前,我得到以下信息:

2020-09-03 15:22:14.105  WARN 480 --- [nio-8080-exec-1] .m.m.a.ExceptionHandlerExceptionResolver : Failure in @ExceptionHandler com.mydomain.common.ExceptionController#handleMyException(Exception)

org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation

这不会使我的 springboot 服务崩溃,但调用不会终止,因此会导致明显的问题。我注意到如果我更改为produces = MediaType.APPLICATION_JSON_STREAM_VALUE,它会非常有效。正如我所期望的那样,它返回与该异常相关的异常和错误消息,但是我们需要将 TEXT_STREAM 用于 SseEmitter 并且我们的消费者期望这种类型的返回。根据我的(有限的)理解,Spring 在响应体中发生了一些神奇的 HttpConversion,那么我需要做什么才能使用produces = MediaType.APPLICATION_JSON_STREAM_VALUE 返回异常?我是否需要编写自己的响应转换器,但看起来...?

【问题讨论】:

标签: java spring-boot spring-mvc media-type


【解决方案1】:

您没有正确终止您的执行人。对 shutdown 的调用不会像您期望的那样做。 ExecutorService 的 javadoc 中的一个示例。

 void shutdownAndAwaitTermination(ExecutorService pool) {
   pool.shutdown(); // Disable new tasks from being submitted
   try {
     // Wait a while for existing tasks to terminate
     if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {
       pool.shutdownNow(); // Cancel currently executing tasks
       // Wait a while for tasks to respond to being cancelled
       if (!pool.awaitTermination(60, TimeUnit.SECONDS))
           System.err.println("Pool did not terminate");
     }
   } catch (InterruptedException ie) {
     // (Re-)Cancel if current thread also interrupted
     pool.shutdownNow();
     // Preserve interrupt status
     Thread.currentThread().interrupt();
   }
 }

一般来说,cachedThread 池应该是共享资源,不应在端点内初始化。 cachedThreadPool 的重点是利用线程重用并避免线程创建失控。如果你真的需要单线程使用newSingleThreadExecutor

我真的不明白你为什么在这里使用执行器。它似乎没有增加任何价值。您只是阻塞了您的请求处理程序线程以在另一个线程中执行代码,而它本来可以在原始线程中执行。

【讨论】:

  • 感谢您指出这一点。我认为其中一些是复制意大利面的糟糕案例,尽管不是我实际问题的答案。
猜你喜欢
  • 1970-01-01
  • 2017-10-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-08
  • 2015-05-08
  • 1970-01-01
  • 2015-11-27
相关资源
最近更新 更多