从 Play 2.4 迁移到 Play 2.5 时 WS 验证器方法出现问题

Issue with a WS verifier method when migrating from Play 2.4 to Play 2.5

我有一个方法需要重构,因为 F.Promise 在 Play 2.5 中已被弃用。它实际上非常可读。它发送请求并通过自定义安全令牌进行身份验证,如果响应为 200,则 returns 为真。

public boolean verify(final String xSassToken){

    WSRequest request = WS.url(mdVerifyXSassTokenURL)
            .setHeader("X-SASS", xSassToken)
            .setMethod("GET");

    final F.Promise<WSResponse> responsePromise = request.execute();

    try {
        final WSResponse response = responsePromise.get(10000);
        int status = response.getStatus();
        if(status == 200 ) { //ok
            return true;
        }
    } catch (Exception e) {
        return false;
    }

    return false;
}

我要做的第一件事就是更改这一行:

final F.Promise<WSResponse> responsePromise = request.execute();

为此:

final CompletionStage<WSResponse> responsePromise = request.execute();

但是,CompletionStage(T) 没有等效的 get() 方法,因此我不确定获取可验证其状态的 WSResponse 的最快和最简单的方法。

是的,不是。至少不是直接的。

您正在做的是 "wrong" 在 PlayFramework 的上下文中。 get 是一个阻塞调用,你应该尽可能避免阻塞。这就是为什么 WS 提供非阻塞 API 和 handle asynchronous results 的方法。因此,首先,您可能应该将 verify 代码重写为异步代码:

public CompletionStage<Boolean> verify(final String xSassToken) {
    return WS.url(mdVerifyXSassTokenURL)
             .setHeader("X-SASS", xSassToken)
             .setMethod("GET")
             .execute()
             .thenApply(response -> response.getStatus() == Http.Status.OK);
}

请注意我是如何使用 thenApply to return a new a java.util.concurrent.CompletionStage 而不是普通布尔值的。这意味着调用 verify 的代码也可以执行相同的操作。例如,您控制器上的操作可以执行以下操作:

public class MyController extends Controller {

    public CompletionStage<Result> action() {
        return verify("whatever").thenApply(success -> {
            if (success) return ok("successful request");
            else return badRequest("xSassToken was not valid");
        });
    }

    public CompletionStage<Boolean> verify(final String xSassToken) { ... }
}

这样您的应用程序将能够处理更大的工作负载而不会挂起。


编辑:

由于您必须保持兼容性,这就是我要改进设计并在迁移时保持代码兼容性的方法:

/**
 * @param xSassToken the token to be validated
 * @return if the token is valid or not
 * 
 * @deprecated Will be removed. Use {@link #verifyToken(String)} instead since it is non blocking.
 */
@Deprecated
public boolean verify(final String xSassToken) {
    try {
        return verifyToken(xSassToken).toCompletableFuture().get(10, TimeUnit.SECONDS);
    } catch (Exception e) {
        return false;
    }
}

public CompletionStage<Boolean> verifyToken(final String xSassToken) {
    return WS.url(mdVerifyXSassTokenURL)
            .setHeader("X-SASS", xSassToken)
            .setMethod("GET")
            .execute()
            .thenApply(response -> response.getStatus() == Http.Status.OK);
}

基本上,弃用旧的 verify 方法并建议用户迁移到新方法。