Play框架 - 未调用ErrorHandler

时间:2017-08-23 22:14:02

标签: java error-handling playframework playframework-2.6

在尝试使用特定方案中的 HttpErrorHandler 机制处理异常时,我在 Play framework(2.6)中遇到了问题。

我在根程序包中有一个简单的 ErrorHandler

import play.Logger;
import play.http.HttpErrorHandler;
import play.mvc.Http;
import play.mvc.Result;
import play.mvc.Results;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;

public class ErrorHandler implements HttpErrorHandler {

    @Override
    public CompletionStage<Result> onClientError(Http.RequestHeader request, int statusCode, String message) {
        Logger.error("client error");
        return CompletableFuture.completedFuture(Results.status(statusCode, "A client error occurred: " + message));
    }

    @Override
    public CompletionStage<Result> onServerError(Http.RequestHeader request, Throwable exception) {
        Logger.error("server error");

        return CompletableFuture.completedFuture(
                Results.internalServerError("A server error occurred: " + exception.getMessage()));
    }
}

我创建了一个自定义控制器来处理资产

package controllers;

import org.apache.commons.lang3.StringUtils;
import play.api.mvc.Action;
import play.api.mvc.AnyContent;
import play.mvc.Controller;

import javax.inject.Inject;

public class AssetsCustomController extends Controller {

    private final Assets assets;

    @Inject
    public AssetsCustomController(Assets assets) {
        this.assets = assets;
    }

    public Action<AnyContent> at(String path, String file) {
        if (StringUtils.isEmpty(path)) {
            throw new IllegalArgumentException();
        }
        return assets.at(path, file, false);
    }
}

我已经检查了 ErrorHandler ,并且除了在 AssetsCustomController 中从此方法抛出异常外,所有情况都正常工作:

public Action<AnyContent> at(String path, String file) {
        if (StringUtils.isEmpty(path)) {
            throw new IllegalArgumentException();
        }
        return assets.at(path, file, false);
    }

例如,当抛出 IllegalArgumentException 时,我的 ErrorHandler 将被忽略,Play将使用其原生错误处理程序。这是堆栈跟踪:

play.api.http.HttpErrorHandlerExceptions$$anon$1: Execution exception[[IllegalArgumentException: null]]
        at play.api.http.HttpErrorHandlerExceptions$.throwableToUsefulException(HttpErrorHandler.scala:255)
        at play.api.http.DefaultHttpErrorHandler.onServerError(HttpErrorHandler.scala:182)
        at play.api.http.DefaultHttpErrorHandler$.onServerError(HttpErrorHandler.scala:286)
        at play.core.server.Server.logExceptionAndGetResult$1(Server.scala:53)
        at play.core.server.Server.getHandlerFor(Server.scala:83)
        at play.core.server.Server.getHandlerFor$(Server.scala:49)
        at play.core.server.AkkaHttpServer.getHandlerFor(AkkaHttpServer.scala:42)
        at play.core.server.AkkaHttpServer.getHandler(AkkaHttpServer.scala:215)
        at play.core.server.AkkaHttpServer.handleRequest(AkkaHttpServer.scala:195)
        at play.core.server.AkkaHttpServer.$anonfun$createServerBinding$3(AkkaHttpServer.scala:107)
Caused by: java.lang.IllegalArgumentException: null
        at controllers.AssetsCustomController.at(AssetsCustomController.java:20)
        at router.Routes$$anonfun$routes$1.$anonfun$applyOrElse$10(Routes.scala:183)
        at play.core.routing.HandlerInvokerFactory$$anon$6$$anon$7.call(HandlerInvoker.scala:61)
        at play.core.routing.GeneratedRouter$$anon$2.call(GeneratedRouter.scala:251)
        at router.Routes$$anonfun$routes$1.$anonfun$applyOrElse$9(Routes.scala:183)
        at play.core.routing.GeneratedRouter.$anonfun$call$5(GeneratedRouter.scala:99)
        at scala.util.Either.fold(Either.scala:118)
        at play.core.routing.GeneratedRouter.call(GeneratedRouter.scala:99)
        at router.Routes$$anonfun$routes$1.applyOrElse(Routes.scala:182)
        at router.Routes$$anonfun$routes$1.applyOrElse(Routes.scala:154)

[溶液]
感谢答案 Flo354 ,我能够解决问题, AssetsCustomController 就是这样:

package controllers;

import akka.stream.Materializer;
import org.springframework.util.StringUtils;
import play.mvc.Controller;
import play.mvc.Result;

import javax.inject.Inject;
import java.util.concurrent.CompletionStage;

public class AssetsCustomController extends Controller {

    private final Assets assets;
    private final Materializer materializer;

    @Inject
    public AssetsCustomController(Materializer materializer, Assets assets) {
        this.materializer = materializer;
        this.assets = assets;
    }

    public CompletionStage<Result> at(String path, String file) {
        if (StringUtils.isEmpty(path)) {
            throw new IllegalArgumentException();
        }
        return assets.at(path, file, false).asJava().apply(request()).run(materializer);
    }
}

1 个答案:

答案 0 :(得分:0)

您的Action<AnyContent>是Scala API的一部分,这意味着它不使用Java部分。

您的自定义错误处理程序仅适用于Java源。查看堆栈跟踪

play.api.http.HttpErrorHandlerExceptions$$anon$1: Execution exception[[IllegalArgumentException: null]]
    at play.api.http.HttpErrorHandlerExceptions$.throwableToUsefulException(HttpErrorHandler.scala:255)
    at play.api.http.DefaultHttpErrorHandler.onServerError(HttpErrorHandler.scala:182)
    at play.api.http.DefaultHttpErrorHandler$.onServerError(HttpErrorHandler.scala:286)
....

当有play.api.something

时,您可以看到它是scala

您可以通过发回CompletionStage<Result>

来解决此问题
public CompletionStage<Result> test(String path, String file) {
    if (StringUtils.isEmpty(path)) {
        throw new IllegalArgumentException();
    }

    return assets.at(path, file, false).asJava().apply(request()).run(materializer);
}

在您的控制器中,不要忘记注入akka.stream.Materializer

的实例

希望它会有所帮助!