玩2.5:获取自定义http动作的响应体

Cab*_*ero 2 java http playframework playframework-2.0 playframework-2.5

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

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

}
Run Code Online (Sandbox Code Playgroud)

Ant*_*ton 6

记录通常被认为是一种交叉功能.在这种情况下,在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);
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

它在做什么?

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

从Play 2.5开始,Akka Streams是首选武器.这意味着一旦你使用了JavaResultExtractor,你将获得一个ByteString,然后你必须解码,以获得真正的字符串.


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