如何在Micronaut过滤器中捕获服务器错误处理?

4
对于由我的Micronaut服务器发出的任何4xx或5xx响应,我想记录响应状态代码和其所针对的端点。过滤器似乎是一个很好的地方来实现此功能,但我似乎无法弄清楚如何插入到onError处理中。
例如,这个过滤器:
@Filter("/**")
class RequestLoggerFilter: OncePerRequestHttpServerFilter() {
  companion object {
    private val log = LogManager.getLogger(RequestLoggerFilter::class.java)
  }

  override fun doFilterOnce(request: HttpRequest<*>, chain: ServerFilterChain): Publisher<MutableHttpResponse<*>>? {
    return Publishers.then(chain.proceed(request), ResponseLogger(request))
  }

  class ResponseLogger(private val request: HttpRequest<*>): Consumer<MutableHttpResponse<*>> {
    override fun accept(response: MutableHttpResponse<*>) {
      log.info("Status: ${response.status.code} Endpoint: ${request.path}")
    }
  }
}

只记录成功响应的日志,而不记录4xx或5xx响应的日志。 我该如何使其连接到onError处理?

你看过 @Error 注解吗?(https://docs.micronaut.io/2.0.1/guide/index.html#errorHandling) - Jeff Scott Brown
我确实查看了错误注释,也许那是解决问题的途径。但如果我创建一个通用的错误处理程序来捕获异常,那似乎就会失去一些很好的默认错误处理功能(例如将io.micronaut.core.convert.exceptions.ConversionErrorException转换为错误请求)。是否有一种方法可以让通用的错误处理程序执行一些日志记录,然后将行为传递给通常会发生的操作呢?<编辑>:我想我真正想要的是进行常规错误处理,然后记录最终结果 - 将400传递到/path - Knut Knutson
3个回答

1
如果您正在尝试处理由ConstraintExceptionHandler产生的400(错误请求)等Micronaut本机异常,您将需要替换bean来完成此操作。
我在这里发布了一个例子如何处理ConstraintExceptionHandler。 如果您只想处理响应本身,则可以使用此映射每个响应代码(例如在@Controller上的示例,因此不确定它是否适用于其他地方,即使具有全局标志)。
@Error(status = HttpStatus.NOT_FOUND, global = true)  
public HttpResponse notFound(HttpRequest request) {
  <...>
}

来自 Micronaut 文档的示例。


1
您可以按照以下步骤操作。创建自己的ApplicationException(扩展RuntimeException),在其中处理应用程序错误,特别是它们如何导致http错误代码。您的异常也可以保存状态码。
示例:
class BadRequestException extends ApplicationException {
 
    public HttpStatus getStatus() {
        return HttpStatus.BAD_REQUEST;
    }
}

您可以为不同的目的拥有多个此ExceptionHandler。

@Slf4j
@Produces
@Singleton
@Requires(classes = {ApplicationException.class, ExceptionHandler.class})
public class ApplicationExceptionHandler implements ExceptionHandler<ApplicationException, HttpResponse> {

    @Override
    public HttpResponse handle(final HttpRequest request, final ApplicationException exception) {
        log.error("Application exception message={}, cause={}", exception.getMessage(), exception.getCause());
        final String message = exception.getMessage();
        final String code = exception.getClass().getSimpleName();
        final ErrorCode error = new ErrorCode(message, code);

        log.info("Status: ${exception.getStatus())} Endpoint: ${request.path}")

        return HttpResponse.status(exception.getStatus()).body(error);
    }
}

0
以下代码用于在错误响应中添加自定义CORS头,在doOnError中您可以记录错误。
@Filter("/**")
public class ResponseCORSAdder implements HttpServerFilter {
    @Override
    public Publisher<MutableHttpResponse<?>> doFilter(HttpRequest<?> request, ServerFilterChain chain) {
            return this.trace(request) 
            .switchMap(aBoolean -> chain.proceed(request))
            .doOnError(error -> {
                if (error instanceof MutableHttpResponse<?>) {
                    MutableHttpResponse<?> res = (MutableHttpResponse<?>) error;
                    addCorsHeaders(res);
                }
            })  
            .doOnNext(res -> addCorsHeaders(res));
    }

        private MutableHttpResponse<?> addCorsHeaders(MutableHttpResponse<?> res) {
            return res
            .header("Access-Control-Allow-Origin", "*")
            .header("Access-Control-Allow-Methods", "OPTIONS,POST,GET")
            .header("Access-Control-Allow-Credentials", "true");
        }

        private Flowable<Boolean> trace(HttpRequest<?> request) {
            return Flowable.fromCallable(() -> { 
                    // trace logic here, potentially performing I/O 
                    return true;
            }).subscribeOn(Schedulers.io()); 
        }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接