【问题标题】:How to access to request body using WebFlux and Netty HttpClient如何使用 WebFlux 和 Netty HttpClient 访问请求正文
【发布时间】:2023-03-06 23:20:01
【问题描述】:

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

ExchangeFilterFunction 不提供对请求正文的访问。

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

  • 我的代码会重复 Spring 在实际发送请求时会执行的操作
  • 不能保证 Spring 作为请求发送的实际字节与我传递给摘要函数的字节相同

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

【问题讨论】:

标签: spring-webflux spring-webclient reactor-netty


【解决方案1】:

目前这在 WebClient 中并不容易。但是有一些方法可以通过在序列化后截取 body 来做到这一点。这可以通过注册一个自定义编码器来完成,该编码器拦截编码后的数据,并将其传递给自定义 HttpConnector 以将其作为标头注入。

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

编辑:目前这篇博文不考虑并发请求。请参阅 Claodio 接受的答案以了解修改后的方法。

【讨论】:

    【解决方案2】:

    我实现了@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

    【讨论】:

    • 这很好。上周并发问题突然出现在我的脑海中,但我很快就忘记了跟进。如果您提出拉取请求,我会将其合并并更新博客文章并注明您的归属
    猜你喜欢
    • 2018-10-07
    • 2012-02-25
    • 2013-05-22
    • 2013-08-13
    • 1970-01-01
    • 1970-01-01
    • 2020-08-14
    • 1970-01-01
    • 2012-07-22
    相关资源
    最近更新 更多