如何使用 WebFlux 和 Netty HttpClient 访问请求 body

How to access to request body using WebFlux and Netty HttpClient

我需要使用 Webflux 的 WebClient 计算请求的某种摘要 body,并且此摘要必须设置为 HTTP header。使用旧的 Spring MVC ClientHttpRequestInterceptor 很容易,因为请求 body 是作为字节数组提供的。

ExchangeFilterFunction 不提供对请求的访问 body。

body 作为 JSon 发送,Spring 使用 Jackson 序列化 Java objects,因此可以选择序列化我的 Object 转化为 Json 并在其上计算摘要,但这种策略有两个缺点:

我想我应该使用 Netty 的一些低级 API,但我找不到任何示例。

目前使用 WebClient 不容易做到这一点。但是有一些方法可以通过拦截 body post-serialization 来做到这一点。这可以通过注册自定义编码器来完成,该编码器在编码后拦截数据,并将其传递给自定义 HttpConnector 以将其作为 header.

注入

这篇博客 post 解释了一种实现方法:https://andrew-flower.com/blog/Custom-HMAC-Auth-with-Spring-WebClient

编辑:目前这个博客post没有考虑并发请求。有关修改后的方法,请参阅 Claodio 接受的答案。

我实施了@rewolf 提出的解决方案并且它有效,但由于 WebFlux 的多线程特性,我遇到了一个问题。

事实上,客户端请求有可能被一个线程保存到线程本地映射中,但另一个线程试图获取它,因此返回空值。

例如,如果要签名的请求是在以 Mono 作为请求主体参数的 Rest 控制器方法中创建的,则会发生这种情况:

@PostMapping
public String execute(@RequestBody Mono<MyBody> body){

    Mono<OtherBody> otherBody = body.map(this::transformBodyIntoOtherBody);

    ...
    webClient.post()
    .body(otherBody)
    .exchange();
    ...
    
}

根据 Reactor 规范,应使用 Reactor Context 而不是 Thread Local。

我 fork @rewolf 项目并实现了一个基于 Reactor Context 的解决方案:https://github.com/taxone/blog-hmac-auth-webclient