从 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
方法并建议用户迁移到新方法。
我有一个方法需要重构,因为 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
方法并建议用户迁移到新方法。