代码之家  ›  专栏  ›  技术社区  ›  Trace

Lagom http status code/header返回为json

  •  0
  • Trace  · 技术社区  · 6 年前

    我有一个示例,其中我向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

    我不确定这是不是个错误,我也不清楚 ServerServiceCall HeaderServiceCall .

    有人能帮忙吗?

    1 回复  |  直到 6 年前
        1
  •  1
  •   Tim Moore    6 年前

    的类型 HeaderServiceCall 定义如下:

    interface HeaderServiceCall<Request,Response>
    

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

    这意味着当您定义响应类型时,返回值应该是 CompletionStage 一个 Pair ResponseHeader 使用响应类型。

    在代码中,响应类型应为 String ,但您将其定义为 Pair<ResponseHeader, String> ,这意味着它希望返回值嵌套: CompletionStage<Pair<ResponseHeader,Pair<ResponseHeader, String>>> . 注意额外的嵌套 配对<ResponseHeader,字符串> .

    与一起使用时 HeaderServiceCall公司 ,这要求您实现 invokeWithHeaders ,将出现编译错误,指示类型不匹配。这是上面截图中的错误。

    当你实施 ServerServiceCall 相反,您的方法被推断为实现 ServiceCall.invoke ,定义为:

    CompletionStage<Response> invoke()
    

    换句话说,方法的返回类型不期望 Pair<ResponseHeader, Response> ,因此您的实现会编译,但会产生不正确的结果。两人包括 负责人 被自动序列化为JSON并以这种方式返回给客户端。

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

    @Override
    public HeaderServiceCall<LoginUser, String> login() {
        return this::loginUser;
    }
    

    你还需要改变 loginUser 方法来接受 RequestHeader 参数,即使它未被使用,以便它与 调用WithHeaders :

    public CompletionStage<Pair<ResponseHeader, String>> loginUser(RequestHeader requestHeader, LoginUser user)
    

    这应该可以解决您的问题,但Lagom服务更典型的做法是直接使用域类型并依赖内置的JSON序列化支持,而不是在服务实现中直接序列化。你也要小心 null 价值观。你不应该还 无效的 负责人 在任何情况下。

    @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 是一个阻塞方法(在调用完成之前不会返回)。在Lagom服务调用中应该避免阻塞,因为它有可能导致性能问题和不稳定。如果这是您控制的代码,则应使用非阻塞样式(返回 完成阶段 ). 如果没有,你应该使用 CompletableFuture.supplyAsync 用一个 完成阶段 ,并在另一个线程池中执行。

    我在GitHub上发现了一个您可能能够适应的示例: https://github.com/dmbuchta/empty-play-authentication/blob/0a01fd1bd2d8ef777c6afe5ba313eccc9eb8b878/app/services/login/impl/FacebookLoginService.java#L59-L74

    推荐文章