Как прочитать тело HttpRequest в Java 11? - PullRequest
0 голосов
/ 23 апреля 2019

В тесте я хотел бы заглянуть внутрь тела запроса HttpRequest. Я хотел бы получить тело в виде строки. Кажется, что единственный способ сделать это - подписаться на BodyPublisher, но как это работает?

Ответы [ 2 ]

2 голосов
/ 23 апреля 2019

Почему бы вам не использовать "официальный" рецепт OpenJDK HttpRequest ?

Первый рецепт делает именно то, что вы хотите:

public void get(String uri) throws Exception {
    HttpClient client = HttpClient.newHttpClient();
    HttpRequest request = HttpRequest.newBuilder()
          .uri(URI.create(uri))
          .build();

    HttpResponse<String> response =
          client.send(request, BodyHandlers.ofString());

    System.out.println(response.body());
}
1 голос
/ 23 апреля 2019

Это интересный вопрос. Где вы берете свой 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);
    }

}
...