如何在 Spring Boot 3 上的 Servlet Filter 中设置自定义响应? (回复好像后来被替换了)

问题描述 投票:0回答:2

我在 Spring Boot 3 中有这个 Filter 类:

@Component
public class AcknowledgeFilter implements jakarta.servlet.Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        // does not work
        ((HttpServletResponse) response).sendError(500, "my-error-message");

        // does not work
        // response.getWriter().write("my-error-message");
        // response.getWriter().flush();
        // or response.getWriter().close();

        // does not work either
        response.getOutputStream().write("my-error-message".getBytes());
        return;
    }
}

该方法返回时不调用

chain.doFilter()
,而是仅设置错误响应,返回正确的 HTTP 代码(500 或 404,...),但不会返回我设置的响应消息(此处为“my-error-message”)。 我总是收到如下 JSON 响应:

{
  "timestamp": "2023-10-17T15:05:12.825+00:00",
  "status": 500,
  "error": "Internal Server Error",
  "path": "/api/myrequest/path"
}

此消息从何而来以及如何覆盖它?

更新

我打开了调试日志记录

o.s.security.web.FilterChainProxy        : Secured GET /api/order/last?customerNumber=123

o.a.c.c.C.[Tomcat].[localhost]           : Processing ErrorPage[errorCode=0, location=/api/error]
s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController#error(HttpServletRequest)
s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController#error(HttpServletRequest)
o.s.security.web.FilterChainProxy        : Securing GET /api/error?customerNumber=123
o.s.security.web.FilterChainProxy        : Secured GET /api/error?customerNumber=123
o.s.web.servlet.DispatcherServlet        : "ERROR" dispatch for GET "/api/error?customerNumber=123", parameters={masked}
s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController#error(HttpServletRequest)
c.a.c.c.c.EndpointLoggingInterceptor     : Endpoint /api/error called
s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController#error(HttpServletRequest)

这说明,错误返回后,由

BasicErrorController
进行处理。看来有必要注册一个自定义的ErrorController。

spring servlet-filters spring-boot-3
2个回答
0
投票

我的解决方案是覆盖 Spring Boots

BaseErrorController
:

import jakarta.servlet.RequestDispatcher;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.boot.autoconfigure.web.ErrorProperties;
import org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController;
import org.springframework.boot.web.servlet.error.DefaultErrorAttributes;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("${server.error.path:${error.path:/error}}")
public class ErrorController extends BasicErrorController {
    public ErrorController() {
        super(new DefaultErrorAttributes(), new ErrorProperties());
    }

    @Override
    @RequestMapping
    public ResponseEntity error(HttpServletRequest request) {
        final String message = (String) request.getAttribute(RequestDispatcher.ERROR_MESSAGE);
        if (!ObjectUtils.isEmpty(message)) {
            final HttpStatus status = getStatus(request);
            final HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            return new ResponseEntity<>(message, headers, status);
        }
        return super.error(request);
    }
}

这当然并不完美,但却是一个有效的快速解决方案。


0
投票

我建议你使用

@ControllerAdvice

这是一个例子

public class CustomException extends RuntimeException {
    public CustomException(String message) {
        super(message);
    }
}

@RestController
@RequestMapping("/example")
public class ExampleController {

    @GetMapping("/error")
    public String triggerError() {
        throw new CustomException("This is a custom exception message.");
    }

    @GetMapping("/ok")
    public String ok() {
        return "Everything is fine.";
    }
}

基于此代码,您可以创建控制器顾问程序,它将捕获您的响应并传输到您的需求

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(CustomException.class)
    @ResponseBody
    public ResponseEntity<SomeObject> handleCustomException(CustomException e) {
        return new ResponseEntity<>(SomeObject.builder().message(e.getMessage()).build(), HttpStatus.INTERNAL_SERVER_ERROR); // you can build your 
    }

    // You can add more exception handlers for other types of exceptions here.

    // You can also define global model attributes here using @ModelAttribute.
}

使用

Lombok
库进行构建器创建

© www.soinside.com 2019 - 2024. All rights reserved.