Lagom http 状态代码 / header 返回为 json
Lagom http status code / header returned as json
我有一个示例,我向 FB api 发出客户端请求以调试令牌请求,然后 return 将结果发送给客户端。
根据访问令牌是否有效,应 return 编辑适当的 header:
@Override
public ServerServiceCall<LoginUser, Pair<ResponseHeader, String>> login() {
return this::loginUser;
}
public CompletionStage<Pair<ResponseHeader, String>> loginUser(LoginUser user) {
ObjectMapper jsonMapper = new ObjectMapper();
String responseString = null;
DebugTokenResponse.DebugTokenResponseData response = null;
ResponseHeader responseHeader = null;
try {
response = fbClient.verifyFacebookToken(user.getFbAccessToken(), config.underlying().getString("facebook.app_token"));
responseString = jsonMapper.writeValueAsString(response);
} catch (ExecutionException | InterruptedException | JsonProcessingException e) {
LOG.error(e.getMessage());
}
if (response != null) {
if (!response.isValid()) {
responseHeader = ResponseHeader.NO_CONTENT.withStatus(401);
} else {
responseHeader = ResponseHeader.OK.withStatus(200);
}
}
return completedFuture(Pair.create(responseHeader, responseString));
}
然而,我得到的结果是:
这不是我所期望的。我期望收到的是 401 的错误 http 状态代码,以及代码中定义的 json 字符串。
不确定为什么我需要 header 响应中的信息 body。
当我想 return 一个 HeaderServiceCall:
时也会出现一个奇怪的错误
我不确定这是否是一个错误,我也不清楚 ServerServiceCall
和 HeaderServiceCall
之间的区别。
有人可以帮忙吗?
HeaderServiceCall
的类型定义如下:
interface HeaderServiceCall<Request,Response>
和
CompletionStage<Pair<ResponseHeader,Response>> invokeWithHeaders(RequestHeader requestHeader,
Request request)
这意味着当你定义一个响应类型时,return 值应该是 CompletionStage
或 ResponseHeader
的 Pair
与响应类型.
在您的代码中,响应类型应为 String
,但您已将其定义为 Pair<ResponseHeader, String>
,这意味着它期望嵌套 return 值:CompletionStage<Pair<ResponseHeader,Pair<ResponseHeader, String>>>
.注意额外的嵌套 Pair<ResponseHeader, String>
.
与 HeaderServiceCall
一起使用时,需要您实现 invokeWithHeaders
,您会收到编译错误,表明类型不匹配。这是您上面的屏幕截图中的错误。
当您改为实施 ServerServiceCall
时,您的方法将被推断为实施 ServiceCall.invoke
,其定义为:
CompletionStage<Response> invoke()
换句话说,return 类型的方法不需要额外的 Pair<ResponseHeader, Response>
,因此您的实现可以编译,但会产生不正确的结果。包含 ResponseHeader
的对会自动序列化为 JSON 并 return 以这种方式发送给客户端。
更正代码需要更改方法签名:
@Override
public HeaderServiceCall<LoginUser, String> login() {
return this::loginUser;
}
您还需要更改 loginUser
方法以接受 RequestHeader
参数,即使它没有被使用,以便它与 invokeWithHeaders
的签名相匹配:
public CompletionStage<Pair<ResponseHeader, String>> loginUser(RequestHeader requestHeader, LoginUser user)
这应该可以解决您的问题,但是 Lagom 服务更典型的做法是直接使用域类型并依赖内置的 JSON 序列化支持,而不是直接在您的服务实现中进行序列化。您还需要注意 null
值。在任何情况下你都不应该 return null
ResponseHeader
。
@Override
public ServerServiceCall<LoginUser, Pair<ResponseHeader, DebugTokenResponse.DebugTokenResponseData>> login() {
return this::loginUser;
}
public CompletionStage<Pair<ResponseHeader, DebugTokenResponse.DebugTokenResponseData>> loginUser(RequestHeader requestHeader, LoginUser user) {
try {
DebugTokenResponse.DebugTokenResponseData response = fbClient.verifyFacebookToken(user.getFbAccessToken(), config.underlying().getString("facebook.app_token"));
ResponseHeader responseHeader;
if (!response.isValid()) {
responseHeader = ResponseHeader.NO_CONTENT.withStatus(401);
} else {
responseHeader = ResponseHeader.OK.withStatus(200);
}
return completedFuture(Pair.create(responseHeader, response));
} catch (ExecutionException | InterruptedException | JsonProcessingException e) {
LOG.error(e.getMessage());
throw e;
}
}
最后,fbClient.verifyFacebookToken
似乎是一种阻塞方法(在调用完成之前它不会 return)。在 Lagom 服务调用中应避免阻塞,因为它有可能导致性能问题和不稳定。如果这是您控制的代码,则应将其编写为使用非阻塞样式(即 return 为 CompletionStage
)。如果没有,你应该使用 CompletableFuture.supplyAsync
将调用包装在 CompletionStage
中,并在另一个线程池中执行它。
我在 GitHub 上找到了这个例子,您也许可以改编:https://github.com/dmbuchta/empty-play-authentication/blob/0a01fd1bd2d8ef777c6afe5ba313eccc9eb8b878/app/services/login/impl/FacebookLoginService.java#L59-L74
我有一个示例,我向 FB api 发出客户端请求以调试令牌请求,然后 return 将结果发送给客户端。
根据访问令牌是否有效,应 return 编辑适当的 header:
@Override
public ServerServiceCall<LoginUser, Pair<ResponseHeader, String>> login() {
return this::loginUser;
}
public CompletionStage<Pair<ResponseHeader, String>> loginUser(LoginUser user) {
ObjectMapper jsonMapper = new ObjectMapper();
String responseString = null;
DebugTokenResponse.DebugTokenResponseData response = null;
ResponseHeader responseHeader = null;
try {
response = fbClient.verifyFacebookToken(user.getFbAccessToken(), config.underlying().getString("facebook.app_token"));
responseString = jsonMapper.writeValueAsString(response);
} catch (ExecutionException | InterruptedException | JsonProcessingException e) {
LOG.error(e.getMessage());
}
if (response != null) {
if (!response.isValid()) {
responseHeader = ResponseHeader.NO_CONTENT.withStatus(401);
} else {
responseHeader = ResponseHeader.OK.withStatus(200);
}
}
return completedFuture(Pair.create(responseHeader, responseString));
}
然而,我得到的结果是:
这不是我所期望的。我期望收到的是 401 的错误 http 状态代码,以及代码中定义的 json 字符串。
不确定为什么我需要 header 响应中的信息 body。
当我想 return 一个 HeaderServiceCall:
时也会出现一个奇怪的错误我不确定这是否是一个错误,我也不清楚 ServerServiceCall
和 HeaderServiceCall
之间的区别。
有人可以帮忙吗?
HeaderServiceCall
的类型定义如下:
interface HeaderServiceCall<Request,Response>
和
CompletionStage<Pair<ResponseHeader,Response>> invokeWithHeaders(RequestHeader requestHeader,
Request request)
这意味着当你定义一个响应类型时,return 值应该是 CompletionStage
或 ResponseHeader
的 Pair
与响应类型.
在您的代码中,响应类型应为 String
,但您已将其定义为 Pair<ResponseHeader, String>
,这意味着它期望嵌套 return 值:CompletionStage<Pair<ResponseHeader,Pair<ResponseHeader, String>>>
.注意额外的嵌套 Pair<ResponseHeader, String>
.
与 HeaderServiceCall
一起使用时,需要您实现 invokeWithHeaders
,您会收到编译错误,表明类型不匹配。这是您上面的屏幕截图中的错误。
当您改为实施 ServerServiceCall
时,您的方法将被推断为实施 ServiceCall.invoke
,其定义为:
CompletionStage<Response> invoke()
换句话说,return 类型的方法不需要额外的 Pair<ResponseHeader, Response>
,因此您的实现可以编译,但会产生不正确的结果。包含 ResponseHeader
的对会自动序列化为 JSON 并 return 以这种方式发送给客户端。
更正代码需要更改方法签名:
@Override
public HeaderServiceCall<LoginUser, String> login() {
return this::loginUser;
}
您还需要更改 loginUser
方法以接受 RequestHeader
参数,即使它没有被使用,以便它与 invokeWithHeaders
的签名相匹配:
public CompletionStage<Pair<ResponseHeader, String>> loginUser(RequestHeader requestHeader, LoginUser user)
这应该可以解决您的问题,但是 Lagom 服务更典型的做法是直接使用域类型并依赖内置的 JSON 序列化支持,而不是直接在您的服务实现中进行序列化。您还需要注意 null
值。在任何情况下你都不应该 return null
ResponseHeader
。
@Override
public ServerServiceCall<LoginUser, Pair<ResponseHeader, DebugTokenResponse.DebugTokenResponseData>> login() {
return this::loginUser;
}
public CompletionStage<Pair<ResponseHeader, DebugTokenResponse.DebugTokenResponseData>> loginUser(RequestHeader requestHeader, LoginUser user) {
try {
DebugTokenResponse.DebugTokenResponseData response = fbClient.verifyFacebookToken(user.getFbAccessToken(), config.underlying().getString("facebook.app_token"));
ResponseHeader responseHeader;
if (!response.isValid()) {
responseHeader = ResponseHeader.NO_CONTENT.withStatus(401);
} else {
responseHeader = ResponseHeader.OK.withStatus(200);
}
return completedFuture(Pair.create(responseHeader, response));
} catch (ExecutionException | InterruptedException | JsonProcessingException e) {
LOG.error(e.getMessage());
throw e;
}
}
最后,fbClient.verifyFacebookToken
似乎是一种阻塞方法(在调用完成之前它不会 return)。在 Lagom 服务调用中应避免阻塞,因为它有可能导致性能问题和不稳定。如果这是您控制的代码,则应将其编写为使用非阻塞样式(即 return 为 CompletionStage
)。如果没有,你应该使用 CompletableFuture.supplyAsync
将调用包装在 CompletionStage
中,并在另一个线程池中执行它。
我在 GitHub 上找到了这个例子,您也许可以改编:https://github.com/dmbuchta/empty-play-authentication/blob/0a01fd1bd2d8ef777c6afe5ba313eccc9eb8b878/app/services/login/impl/FacebookLoginService.java#L59-L74