【问题标题】:Play 2.5: get response body in custom http action玩 2.5:在自定义 http 动作中获取响应体
【发布时间】:2016-03-14 11:47:32
【问题描述】:

我正在尝试创建自定义 http 操作 (https://playframework.com/documentation/2.5.x/JavaActionsComposition) 以使用 Play 2.5.0 Java 记录请求和响应正文。这是我到目前为止所得到的:

public class Log extends play.mvc.Action.Simple {

    public CompletionStage<Result> call(Http.Context ctx) {
        CompletionStage<Result> response = delegate.call(ctx);
        //request body is fine
        System.out.println(ctx.request().body().asText())
        //how to get response body string here while also not sabotaging http response flow of the framework?
        //my guess is it should be somehow possible to access it below?
        response.thenApply( r -> {
            //???
            return null;
        });
        return response;
    }

}

【问题讨论】:

    标签: java http playframework playframework-2.0 playframework-2.5


    【解决方案1】:

    日志记录通常被认为是一种跨领域功能。在这种情况下,在 Play 中执行此操作的首选方法是使用过滤器:

    过滤器 API 旨在用于不加选择地应用于所有路由的横切关注点。例如,以下是过滤器的一些常见用例:

    • 日志记录/指标收集
    • GZIP 编码
    • 安全标头

    这对我有用:

    import java.util.concurrent.CompletionStage;
    import java.util.function.Function;
    import javax.inject.Inject;
    import akka.stream.*;
    import play.Logger;
    import play.mvc.*;
    
    public class LoggingFilter extends Filter {
    
        Materializer mat;
    
        @Inject
        public LoggingFilter(Materializer mat) {
            super(mat);
            this.mat = mat;
        }
    
        @Override
        public CompletionStage<Result> apply(
                Function<Http.RequestHeader, CompletionStage<Result>> nextFilter,
                Http.RequestHeader requestHeader) {
            long startTime = System.currentTimeMillis();
            return nextFilter.apply(requestHeader).thenApply(result -> {
                long endTime = System.currentTimeMillis();
                long requestTime = endTime - startTime;
    
                Logger.info("{} {} took {}ms and returned {}",
                    requestHeader.method(), requestHeader.uri(), requestTime, result.status());
                akka.util.ByteString body = play.core.j.JavaResultExtractor.getBody(result, 10000l, mat);
                Logger.info(body.decodeString("UTF-8"));
    
                return result.withHeader("Request-Time", "" + requestTime);
            });
        }
    }
    

    它在做什么?

    首先,这会创建一个新的过滤器,它可以与您可能拥有的其他过滤器一起使用。为了获取响应的正文,我们实际上使用了nextFilter - 一旦我们得到响应,我们就可以获取正文。

    从 Play 2.5 开始,Akka Streams 是首选武器。这意味着一旦您使用JavaResultExtractor,您将得到一个ByteString,然后您必须对其进行解码才能获得下面的真实字符串。


    请记住,在您正在创建的Action 中复制此逻辑应该没有问题。我只是选择了Filter 的选项,因为我的帖子顶部说明了原因。

    【讨论】:

    • 正如你在上面写的 akka.util.ByteString body = play.core.j.JavaResultExtractor.getBody(result, 10000l, mat);这将从响应结果对象中获取数据,是否有任何方法可以在过滤器中获取请求正文并在正文中进行一些更改并发送到控制器?
    • 并非如此。问题是过滤器知道请求标头但不知道请求正文 - 因为此时尚未处理正文。处理标头是因为 Play 是一个反应式框架 - 无需阻塞和等待正文。要操作请求正文,您必须使用操作组合 (playframework.com/documentation/2.5.x/JavaActionsComposition)。如果您有一些具体问题/想了解更多信息,请打开一个新问题,以免我们劫持此主题
    猜你喜欢
    • 1970-01-01
    • 2020-01-14
    • 2015-10-18
    • 1970-01-01
    • 2017-12-10
    • 2013-02-09
    • 1970-01-01
    • 2017-04-28
    • 2016-05-27
    相关资源
    最近更新 更多