【问题标题】:Consuming custom error response from Spring REST使用来自 Spring REST 的自定义错误响应
【发布时间】:2020-07-25 16:54:31
【问题描述】:

我想为带有消息的错误代码实现自定义错误页面。 到目前为止,按照 baeldung 指南,我在后端得到了这个;

自定义异常:

 public class TicketNotFoundException extends RuntimeException
{
    public TicketNotFoundException(Long id)
    {
        super("Ticket not found with id: "+id);
    }
}

自定义响应:

public class CustomErrorResponse
{
    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd hh:mm:ss")
    private LocalDateTime timestamp;
    private int status;
    private String error;
//getters setters
 }

自定义异常处理程序:

@ControllerAdvice
public class CustomGlobalExceptionHandler extends ResponseEntityExceptionHandler
{

    @ExceptionHandler(value = TicketNotFoundException.class)
    public ResponseEntity<CustomErrorResponse> customHandleNotFound(Exception ex)
    {
        CustomErrorResponse errors = new CustomErrorResponse();
        errors.setTimestamp(LocalDateTime.now());
        errors.setError(ex.getMessage());
        errors.setStatus(HttpStatus.NOT_FOUND.value());
        return new ResponseEntity<>(errors, HttpStatus.NOT_FOUND);
    }
}

并且响应本身有效:

{ 时间戳:“2020-04-13 09:33:52”,状态:404,错误:“票不是 找到 id: 1" }

后端终端:

 Resolved [com.eggorko.ebt.ticket.TicketNotFoundException: Ticket not found with id: 1] 

所以我的问题是我应该在客户端做什么?

客户端控制器如下所示:

@GetMapping("/{id}")
    public String ticket(@PathVariable Long id, Model model)
    {
        String url = "http://localhost:8080/api/ticket/";
        ResponseEntity<Ticket> ticket = restTemplate.getForEntity( url+ id, Ticket.class);

        model.addAttribute("ticket",ticket.getBody());
        model.addAttribute("title","Tickets");
        return "ticket";
    }

我做了一点客户端,但它不起作用:

@Controller
public class MyErrorController implements ErrorController
{
    @RequestMapping("/error")
    public String handleError(HttpServletRequest  request)
    {
        Object status = request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE);

        if (status != null) {
            Integer statusCode = Integer.valueOf(status.toString());

            if(statusCode == HttpStatus.NOT_FOUND.value()) {
                return "error-404";
            }
            else if(statusCode == HttpStatus.INTERNAL_SERVER_ERROR.value()) {
                return "error-500";
            }
        }
        return "error";
    }

    @Override
    public String getErrorPath()
    {
        return "/error";
    }
}

这是我在客户端的终端中得到的:

2020-04-13 10:34:40.559 ERROR 12868 --- [nio-8081-exec-8] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.web.client.HttpClientErrorException$NotFound: 404 : [{"timestamp":"2020-04-13 10:34:40","status":404,"error":"Ticket not found with id: 1"}]] with root cause

它会转到 500 错误页面,而不是 404。

我有点理解为什么它不起作用。我在客户端没有任何处理错误,它进入错误 500。但我不知道如何处理它。

更新
所以我这样做了:

 String url = "http://localhost:8080/api/ticket/";
            try {
                ResponseEntity<Ticket> ticket = restTemplate.getForEntity(url + id, Ticket.class);
                model.addAttribute("ticket",ticket.getBody());
                model.addAttribute("title","Tickets");
            }catch (Exception e)
            {
                String msg = e.getMessage();
                model.addAttribute("message",msg);
                return "/error";
            }
   return "ticket";

现在至少我得到了一个错误页面,其中包含来自后端的实际消息。但是这个解决方案正在解决 MyErrorController。 MyErrorController 不会触发并且基本上已过时。

【问题讨论】:

    标签: java spring spring-boot rest error-handling


    【解决方案1】:

    您正在从 MyErrorController 返回视图名称,您在视图解析器中指定的位置是否有错误页面 errro.html 或 error.jsp(您为视图解析器使用的任何后缀)?此外,您对所有错误代码使用相同的错误页面,您可以为不同的错误代码创建多个错误页面,例如 error-404.jsp 和 error-500.jsp。另一种方法是返回ModelAndView而不是视图名,可以参考link

    更新

    好的,现在我知道你想要实现什么,它给出 500,因为你没有在客户端控制器中处理异常,当你进行休息模板调用时,你说我想要一个 Ticket 类型的响应,但你得到CustomErrorResponse 的响应,通过控制台日志或捕获异常确定它抛出的异常,然后处理它并进行处理。

    @GetMapping("/{id}")
        public String ticket(@PathVariable Long id, Model model)
        {
            String url = "http://localhost:8080/api/ticket/";
            try
            {
            ResponseEntity<Ticket> ticket = restTemplate.getForEntity( url+ id, 
            Ticket.class);
            }
            catch(Exception e)
            {
             // handel exception
            }
    
            model.addAttribute("ticket",ticket.getBody());
            model.addAttribute("title","Tickets");
            return "ticket";
        }
    

    您可以包装您的 Ticket 并且 CustomErrorResponse 是一个父类,然后可以使用实例来确定您收到的响应

    ResponseEntity<Parent> parent= restTemplate.getForEntity( url+ id, 
            Parent.class);
    if(parent.getBody() instanceof Ticket)
    {
    //normal flow
    }
    else
    {
    //error
    }
    
    

    更新2

    ErrorController 已过时,因为

    String url = "http://localhost:8080/api/ticket/";
                try {
                    ResponseEntity<Ticket> ticket = restTemplate.getForEntity(url + id, Ticket.class);
                    model.addAttribute("ticket",ticket.getBody());
                    model.addAttribute("title","Tickets");
                }catch (Exception e)
                {
                    String msg = e.getMessage();
                    model.addAttribute("message",msg);
                    return "/error";
                }
       return "ticket";
    

    返回一个带有模型的视图error.jsp(或.html),它没有重定向到URL /error,你可以通过使用redirect see来做到这一点,但我建议不要这样做,你的ErrorController是故意的在您的应用程序中发生错误,而不是在您的应用程序调用的某个应用程序中,针对这种情况实施适当的响应页面。

    编码愉快!

    【讨论】:

    • 是的,所有的观点都在那里。同样的“错误”事情,这只是我试图做的事情,我把它改回了它应该是的样子。我不太清楚问题是什么,我将编辑帖子。
    • 我快到了。谢谢您的帮助。我会更新我所做的。
    猜你喜欢
    • 2015-09-04
    • 2012-05-22
    • 2019-04-03
    • 2014-12-01
    • 2014-04-16
    • 1970-01-01
    • 1970-01-01
    • 2015-05-20
    相关资源
    最近更新 更多