5

在测试中,我想查看 HttpRequest 的主体内部。我想把身体作为一个字符串。似乎这样做的唯一方法是订阅 BodyPublisher ,但它是如何工作的?

4

1 回答 1

11

这是个有趣的问题。你从哪里得到你HttpRequest的?最简单的方法是直接从创建 HttpRequest 的代码中获取正文。如果这不可能,那么接下来就是克隆该请求并将其主体发布者包装在您自己的实现中,BodyPublisher然后再通过 HttpClient 发送请求。HttpRequest编写一个包装另一个实例HttpRequest并将每个调用委托给包装实例的子类应该相对容易(如果乏味) ,但重写HttpRequest::bodyPublisher以执行以下操作:

return request.bodyPublisher().map(this::wrapBodyPublisher);

否则,您可能还尝试订阅请求正文发布者并从中获取正文字节 - 但请注意,并非所有实现都BodyPublisher可能支持多个订阅者(无论是并发的还是顺序的)。

为了说明我上面的建议:根据正文发布者的具体实现,类似下面的内容可能会起作用,并且前提是您可以防止并发订阅正文发布者。也就是说 - 在您了解所有各方的受控测试环境中,它可能是可行的。不要在生产中使用任何东西:

public class HttpRequestBody {

    // adapt Flow.Subscriber<List<ByteBuffer>> to Flow.Subscriber<ByteBuffer>
    static final class StringSubscriber implements Flow.Subscriber<ByteBuffer> {
        final BodySubscriber<String> wrapped;
        StringSubscriber(BodySubscriber<String> wrapped) {
            this.wrapped = wrapped;
        }
        @Override
        public void onSubscribe(Flow.Subscription subscription) {
            wrapped.onSubscribe(subscription);
        }
        @Override
        public void onNext(ByteBuffer item) { wrapped.onNext(List.of(item)); }
        @Override
        public void onError(Throwable throwable) { wrapped.onError(throwable); }
        @Override
        public void onComplete() { wrapped.onComplete(); }
    }

    public static void main(String[] args) throws Exception {
        var request = HttpRequest.newBuilder(new URI("http://example.com/blah"))
                .POST(BodyPublishers.ofString("Lorem ipsum dolor sit amet"))
                .build();

        // you must be very sure that nobody else is concurrently 
        // subscribed to the body publisher when executing this code,
        // otherwise one of the subscribers is likely to fail.
        String reqbody = request.bodyPublisher().map(p -> {
            var bodySubscriber = BodySubscribers.ofString(StandardCharsets.UTF_8);
            var flowSubscriber = new StringSubscriber(bodySubscriber);
            p.subscribe(flowSubscriber);
            return bodySubscriber.getBody().toCompletableFuture().join();
        }).get();
        System.out.println(reqbody);
    }

}
于 2019-04-23T17:38:53.870 回答