【问题标题】:Call manually PlayFramework custom error page手动调用 PlayFramework 自定义错误页面
【发布时间】:2016-04-07 07:24:25
【问题描述】:

我在 PlayFramework 中实现了自定义页面,就像文档中所说的那样:https://www.playframework.com/documentation/2.4.x/JavaErrorHandling

我在 application.conf 中添加了对 ErrorHandler 的引用

play.http.errorHandler = "com.company.ErrorHandler"

我自己实现了 ErrorHandler:

public class ErrorHandler extends DefaultHttpErrorHandler {

    @Inject
    public ErrorHandler(Configuration configuration, Environment environment, OptionalSourceMapper sourceMapper, Provider<Router> routes) {
        super(configuration, environment, sourceMapper, routes);
    }

    @Override
    public F.Promise<Result> onClientError(Http.RequestHeader requestHeader, int errorCode, String message) {
        Logger.debug("Error: onClientError : " + errorCode + ", message: " + message);
        return super.onClientError(requestHeader, errorCode, message);
    }

    @Override
    public F.Promise<Result> onServerError(Http.RequestHeader request, Throwable exception) {
        Logger.debug("Error: onServerError general");
        return F.Promise.pure(redirect(com.company.routes.ErrorController.serverErrorPage()));
    }

    @Override
    protected F.Promise<Result> onBadRequest(Http.RequestHeader request, String message) {
        Logger.debug("Error: onBadRequest, message: " + message);
        return F.Promise.pure(redirect(com.company.routes.ErrorController.badRequestPage()));
    }

    @Override
    protected F.Promise<Result> onForbidden(Http.RequestHeader request, String message) {
        Logger.debug("Error: onForbidden, message: " + message);
        return F.Promise.pure(redirect(com.company.routes.ErrorController.forbiddenPage()));
    }

    @Override
    protected F.Promise<Result> onNotFound(Http.RequestHeader request, String message) {
        Logger.debug("Error: onNotFound, message: " + message);
        return F.Promise.pure(redirect(com.company.routes.ErrorController.notFoundPage()));
    }

    @Override
    protected F.Promise<Result> onOtherClientError(Http.RequestHeader request, int statusCode, String message) {
        Logger.debug("Error: onOtherClientError, message: " + message);
        return F.Promise.pure(redirect(com.company.routes.ErrorController.errorDefaultPage()));
    }
}

当框架本身抛出错误时,自定义页面效果很好。

虽然我在从控制器重定向到错误页面时遇到问题。当我调用端点时:

public Result contact() {
    return Results.forbidden("Forbidden");
}

没有显示来自 ErrorHander 的错误页面。我只看到文字“禁止”。

如何在不显式重定向的情况下显示我的自定义错误页面?

【问题讨论】:

    标签: java scala playframework playframework-2.4


    【解决方案1】:

    我遇到了类似的问题,我通过覆盖 onClientError 并切换到不同的 HTTP 状态代码来解决它:

    public class ErrorHandler extends DefaultHttpErrorHandler {
    
      @Inject
      public ErrorHandler(Configuration configuration, Environment environment,
            OptionalSourceMapper sourceMapper, Provider<Router> routes) {
          super(configuration, environment, sourceMapper, routes);
      }
    
      @Override
      public Promise<Result> onClientError(RequestHeader request, int statusCode,
            String message) {
        switch (statusCode) {
        case Http.Status.BAD_REQUEST:
            Logger.info(CLASS_NAME + ".onBadRequest: " + message);
            return Promise.<Result> pure(
                    Results.badRequest(views.html.error.render("Bad request")));
        case Http.Status.NOT_FOUND:
            Logger.info(CLASS_NAME + ".onNotFound: Requested page \""
                    + request.uri() + "\" couldn't be found.");
            return Promise.<Result> pure(
                    Results.notFound(views.html.error.render("Requested page \""
                            + request.uri() + "\" couldn't be found.")));
        case Http.Status.FORBIDDEN:
            Logger.info(CLASS_NAME + ".onForbidden: " + message);
            return Promise.<Result> pure(Results
                    .forbidden("You're not allowed to access this resource."));
        default:
            Logger.info(CLASS_NAME + ".onClientError: HTTP status code "
                    + statusCode + ", " + message);
            return Promise.<Result> pure(Results.status(statusCode,
                    views.html.error.render("Internal server error")));
        }
      }
    
      @Override
      public Promise<Result> onServerError(RequestHeader request,
            Throwable exception) {
        Logger.info(CLASS_NAME + ".onServerError: Internal server error",
                exception);
        return Promise.<Result> pure(Results.internalServerError(
                views.html.error.render("Internal server error")));
      }
    
    }
    

    也许它甚至是 Play 文档中的一个错误?至少在HttpErrorHandler 接口中,除了onServerErroronClientError (https://www.playframework.com/documentation/2.4.0/api/java/play/http/HttpErrorHandler.html) 之外,它没有谈论其他方法。

    【讨论】:

    • 这很好。但是,如果您检查 DefaultHttpErrorHandler 的底层实现,那么您会注意到它已经将 onClientError 中的调用重定向到其他方法,例如 for e.g. onBadRequest,onForbidden。我的问题是,尽管返回了结果。禁止()。自定义 ErrorHandler 未捕获该请求。
    • 你似乎是对的。也许它适用于 Play 2.5 - 与 2.4 相比,它们在 DefaultHttpErrorHandler 中发生了很大变化。
    【解决方案2】:

    我找到了一种通过将客户端错误注入所需元素来直接调用客户端错误的方法。我最终得到了以下解决方案(Play Framework 2.5):

    public class ErrorHandler extends DefaultHttpErrorHandler {
    
        private ErrorController errorController;
    
        @Inject
        public ErrorHandler(Configuration configuration,
                            Environment environment,
                            OptionalSourceMapper sourceMapper,
                            Provider<Router> routes,
                            ErrorController errorController) {
            super(configuration, environment, sourceMapper, routes);
    
            this.errorController = errorController;
        }
    
        @Override
        public CompletionStage<Result> onServerError(Http.RequestHeader request, Throwable exception) {
            Logger.debug("Error: onServerError general");
            return CompletableFuture.completedFuture(this.errorController.serverErrorPage());
        }
    
        @Override
        protected CompletionStage<Result> onBadRequest(Http.RequestHeader request, String message) {
            Logger.debug("Error: onBadRequest, message: " + message);
            return CompletableFuture.completedFuture(this.errorController.badRequestPage());
        }
    
        @Override
        protected CompletionStage<Result> onForbidden(Http.RequestHeader request, String message) {
            Logger.debug("Error: onForbidden, message: " + message);
            return CompletableFuture.completedFuture(this.errorController.forbiddenPage());
        }
    
        @Override
        protected CompletionStage<Result> onNotFound(Http.RequestHeader request, String message) {
            Logger.debug("Error: onNotFound, message: " + message);
            return CompletableFuture.completedFuture(this.errorController.notFoundPage());
        }
    
        @Override
        protected CompletionStage<Result> onOtherClientError(Http.RequestHeader request, int statusCode, String message) {
            Logger.debug("Error: onOtherClientError, message: " + message);
            return CompletableFuture.completedFuture(this.errorController.errorDefaultPage());
        }
    }
    

    那我可以这样称呼它:

    class SomeElement  {
    
        private final DefaultHttpErrorHandler errorHandler;
    
        @Inject
        public SomeElement(DefaultHttpErrorHandler errorHandler) {
            this.errorHandler = errorHandler;
        }
    
        public CompletionStage<Result> onAuthFailure(final Http.Context context,
                                                     final Optional<String> content) {
            return this.errorHandler.onClientError(context.request(), Http.Status.FORBIDDEN, "You don't have required permissions.");
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-10-15
      • 2015-08-26
      • 2013-08-26
      • 2014-02-28
      • 2016-04-25
      • 2013-02-27
      • 1970-01-01
      相关资源
      最近更新 更多