Lagom http状态代码/标头作为json返回

时间:2018-08-05 20:43:56

标签: lagom

我有一个示例,我向客户端发出请求以调试对FB api的令牌请求,然后将结果返回给客户端。
根据访问令牌是否有效,应返回适当的标头:

@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));
}

但是,我得到的结果是:

enter image description here

这不是我真正期望的。我希望收到的是错误的HTTP状态代码401,以及代码中定义的json字符串。
不知道为什么我在响应正文中需要标题信息。

当我想返回HeaderServiceCall时,还会发生一个奇怪的错误:

enter image description here

我不确定这是否是错误,也不清楚ServerServiceCallHeaderServiceCall之间的区别。

有人可以帮忙吗?

1 个答案:

答案 0 :(得分:1)

HeaderServiceCall的类型是这样定义的:

interface HeaderServiceCall<Request,Response>

CompletionStage<Pair<ResponseHeader,Response>> invokeWithHeaders(RequestHeader requestHeader,
                                                                 Request request)

这意味着在定义响应类型时,返回值应该是具有响应类型的CompletionStage的{​​{1}}中的Pair

在您的代码中,响应类型应该为ResponseHeader,但是您已将其定义为String,这意味着它期望嵌套返回值:Pair<ResponseHeader, String>。请注意额外的嵌套CompletionStage<Pair<ResponseHeader,Pair<ResponseHeader, String>>>

当与Pair<ResponseHeader, String>一起使用时,需要实现HeaderServiceCall,会出现编译错误,指示类型不匹配。这是您上面的屏幕截图中的错误。

当您实施invokeWithHeaders时,您的方法被推断为实施ServiceCall.invoke,其定义为:

ServerServiceCall

换句话说,该方法的返回类型不需要附加的CompletionStage<Response> invoke() ,因此您的实现可以编译,但是会产生错误的结果。包含Pair<ResponseHeader, Response>的货币对会自动序列化为JSON,并以这种方式返回给客户端。

更正代码需要更改方法签名:

ResponseHeader

您还需要更改@Override public HeaderServiceCall<LoginUser, String> login() { return this::loginUser; } 方法以接受loginUser参数,即使该参数未使用,也要与RequestHeader的签名匹配:

invokeWithHeaders

这应该可以解决您的问题,但是对于Lagom服务而言,更直接地使用域类型并依赖于内置的JSON序列化支持,而不是直接在服务实现中进行序列化,这将更为典型。您还需要注意public CompletionStage<Pair<ResponseHeader, String>> loginUser(RequestHeader requestHeader, LoginUser user) 值。在任何情况下,您都不应返回null 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; } } 是一个阻塞方法(直到调用完成才返回)。在Lagom服务呼叫中应避免阻塞,因为它可能导致性能问题和不稳定。如果这是您控制的代码,则应将其编写为使用非阻塞样式(返回fbClient.verifyFacebookToken)。如果不是,则应使用CompletableFuture.supplyAsync将调用包装在CompletionStage中,然后在另一个线程池中执行。

我在GitHub上发现了这个示例,您也许可以对其进行调整:https://github.com/dmbuchta/empty-play-authentication/blob/0a01fd1bd2d8ef777c6afe5ba313eccc9eb8b878/app/services/login/impl/FacebookLoginService.java#L59-L74