如何在 Java 11 中读取 HttpRequest 的 body?
How to read the body of a HttpRequest in Java 11?
在测试中,我想查看 HttpRequest 的 body 内部。我想将 body 作为字符串获取。似乎唯一的方法就是订阅 BodyPublisher,但它是如何工作的?
这是一个有趣的问题。你从哪里得到你的HttpRequest
?最简单的方法是直接从创建 HttpRequest 的代码中获取主体。如果这不可能,那么下一步就是克隆该请求并将其主体发布者包装在您自己的 BodyPublisher
实现中,然后再通过 HttpClient 发送请求。编写 HttpRequest
的子类包装 HttpRequest
的另一个实例并将每次调用委托给包装的实例应该相对容易(如果乏味的话),但是覆盖 HttpRequest::bodyPublisher
来做类似的事情:
return request.bodyPublisher().map(this::wrapBodyPublisher);
否则,您也可以尝试订阅请求正文发布者并从中获取正文字节 - 但请注意,并非所有 BodyPublisher
的实现都支持多个订阅者(无论是并发还是顺序)。
为了说明我上面的建议:下面的内容可能会起作用,具体取决于 body publisher 的具体实现,并且前提是您可以防止对 body publisher 的并发订阅。也就是说——在一个你了解所有各方的受控测试环境中,它可能是可行的。不要在生产中使用任何东西:
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);
}
}
在测试中,我想查看 HttpRequest 的 body 内部。我想将 body 作为字符串获取。似乎唯一的方法就是订阅 BodyPublisher,但它是如何工作的?
这是一个有趣的问题。你从哪里得到你的HttpRequest
?最简单的方法是直接从创建 HttpRequest 的代码中获取主体。如果这不可能,那么下一步就是克隆该请求并将其主体发布者包装在您自己的 BodyPublisher
实现中,然后再通过 HttpClient 发送请求。编写 HttpRequest
的子类包装 HttpRequest
的另一个实例并将每次调用委托给包装的实例应该相对容易(如果乏味的话),但是覆盖 HttpRequest::bodyPublisher
来做类似的事情:
return request.bodyPublisher().map(this::wrapBodyPublisher);
否则,您也可以尝试订阅请求正文发布者并从中获取正文字节 - 但请注意,并非所有 BodyPublisher
的实现都支持多个订阅者(无论是并发还是顺序)。
为了说明我上面的建议:下面的内容可能会起作用,具体取决于 body publisher 的具体实现,并且前提是您可以防止对 body publisher 的并发订阅。也就是说——在一个你了解所有各方的受控测试环境中,它可能是可行的。不要在生产中使用任何东西:
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);
}
}