【问题标题】:springboot return 200 when close Closeable even throw exception关闭可关闭甚至抛出异常时,弹簧启动返回200
【发布时间】:2021-11-17 13:34:40
【问题描述】:

如何在springboot中返回错误并关闭Closeable类? 当我在 springboot 中遇到一些错误并关闭一个可关闭的类时返回 200 OK

我不需要关闭 Closeable 吗?有没有办法在springboot上处理这个?


   CSVPrinter csvPrinter;

    try{

        csvPrinter = new CSVPrinter(httpServletResponse.getWriter() , CSVFormat.DEFAULT);

        System.out.println(1/0); // force exception to jump into catch

    }catch (Exception e) {

        e.printStackTrace();

        try { csvPrinter.close(true); } catch (IOException e1) { e1.printStackTrace(); } // has returned 200 OK when closing CSVPrinter
         
        throw new RuntimeException("Error"); // this are been called but was already returned 200
    }


我尝试过 try-with-resources 但也没有成功

    try( final CSVPrinter csvPrinter = new CSVPrinter( httpServletResponse.getWriter() , CSVFormat.DEFAULT) ){

        System.out.println(1/0); // // force exception to jump into catch

    }catch (Exception e) {  // has returned 200 OK 
        throw new RuntimeException("Error"); // this are been called but was already returned 200
    }

我在控制器中注入 httpResponse

  @GetMapping("/export")
   public void exportInCsv(
                ExportRequest exportRequest,
                HttpServletResponse httpServletResponse // inject httpreponse
             ){

        exportService.writeResponse(exportRequest,httpServletResponse);
    }

我没有控制器异常处理程序

【问题讨论】:

  • 我不完全理解你的问题。 “我已经尝试过尝试资源但没有成功”是什么意思
  • 我用try-with-resources 刷新了添加示例的帖子,但我得到了 200 OK 甚至抛出任何异常
  • 如果异常真的被抛出,这是不可能的。你能展示整个 RestController 吗?你定义了 ExceptionHandler 吗?
  • 我不知道为什么会这样。我用控制器和处理程序异常信息刷新了帖子
  • 为什么要直接写回复?

标签: spring-boot try-catch autocloseable


【解决方案1】:

您的控制器方法 (exportInCsv()) 实际上并未返回 ResponseEntity 对象,因此向此端点发出的 GET 请求将始终导致 200 响应。

你应该抛出一个检查异常作为失败的结果(构造或关闭CSVPrinter的一个实例),或者在你的代码中更一般地实现ResponseEntityExceptionHandler来捕获未经检查的异常并用一个通用的响应错误消息(和400)。

就个人而言,我更喜欢前一种做事方式,因为代码最终会更加明确,并允许您对端点进行更多自定义(但两者都做并不是一个坏主意)。

伪代码

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;


import java.util.UUID;


@RestController
@RequestMapping("/widgets")
public class WidgetController {

    @GetMapping(value = "/{widgetId}", produces = "application/json")
    public ResponseEntity<?> fetchWidget(@PathVariable UUID widgetId) {
        try {
            Widget widget = findWidgetById(widgetId);

            return ResponseEntity.ok().body(widget);
        } catch (CheckedException e) {
            return ResponseEntity.badRequest().build();
        }
    }

    private Widget findWidgetById(UUID widgetId) throws CheckedException {
        Widget widget = findMethodThatMightThrowCheckedException(widgetId);

        return widget;
    }

}

对于已检查的异常,您还可以选择在较低级别处理它(更接近最初抛出的位置),但听起来您想将其冒泡(并将其映射到 HTTP 响应)以GET /export API 的客户端。

【讨论】:

  • 我尝试返回 ResponseEntity&lt;Void&gt; 或使用检查的异常然后得到相同的结果。除了关闭可关闭并返回 200 的 try 语句之外,所有服务中的所有错误都得到了完美处理
  • 我真的需要更改所有实现服务和库来处理下载返回ResponseEntity&lt;Resource&gt; 吗?有没有办法在 httpresponse 中写这篇文章,如果我在 try-with-resource spring-boot 中遇到一些错误,在跳转到 catch 之前不要返回 200?
  • 您是否尝试过将您的 CSV 编写逻辑抽象为一个方法并为该方法编写测试?应该可以在方法或服务的(较低)级别隔离意外行为,而不是仅仅依靠控制器生成的 HTTP 响应代码来获取反馈。
猜你喜欢
  • 2018-04-27
  • 1970-01-01
  • 1970-01-01
  • 2011-12-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-14
  • 1970-01-01
相关资源
最近更新 更多