Spring Boot 3中WebClient或HTTP接口是否存在Feign.RequestInterceptor等价接口?
Spring Boot 3 中 WebClient/HTTP 接口的请求拦截方案(等价于 Feign.RequestInterceptor)
在Spring Boot 3环境下,WebClient和RestTemplate(对应传统同步HTTP接口场景)都提供了与Feign.RequestInterceptor功能等价的拦截机制,以下是具体实现方案:
一、WebClient 对应拦截方案:ExchangeFilterFunction
WebClient使用ExchangeFilterFunction作为请求拦截器,可在请求发送前修改请求实例,完全覆盖Feign.RequestInterceptor的功能。对应你提供的Feign拦截器逻辑,实现示例如下:
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.context.request.RequestAttributes; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.reactive.function.client.ExchangeFilterFunction; import org.springframework.web.reactive.function.client.ClientRequest; import org.springframework.web.reactive.function.client.ClientResponse; import reactor.core.publisher.Mono; import java.util.UUID; public class TokenWebClientFilter implements ExchangeFilterFunction { private static final Logger LOG = LoggerFactory.getLogger(TokenWebClientFilter.class); public static final String TOKEN_HEADER_NAME = "my-token"; @Override public Mono<ClientResponse> filter(ClientRequest request, ExchangeFunction next) { String traceToken = computeTraceTokenIfAbsent(); // 修改请求,添加token头 ClientRequest modifiedRequest = ClientRequest.from(request) .header(TOKEN_HEADER_NAME, traceToken) .build(); return next.exchange(modifiedRequest); } private String computeTraceTokenIfAbsent() { try { var attribute = RequestContextHolder.currentRequestAttributes() .getAttribute(TOKEN_HEADER_NAME, RequestAttributes.SCOPE_REQUEST); if (attribute instanceof String strAttribute) { RequestContextHolder.currentRequestAttributes() .setAttribute(TOKEN_HEADER_NAME, strAttribute, RequestAttributes.SCOPE_REQUEST); return strAttribute; } } catch (IllegalStateException e) { LOG.debug("Not in a request context: Creating new token for outgoing request.", e); } return UUID.randomUUID().toString(); } }
配置WebClient时注册该过滤器:
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.reactive.function.client.WebClient; @Configuration public class WebClientConfig { @Bean public WebClient webClient(TokenWebClientFilter tokenFilter) { return WebClient.builder() .filter(tokenFilter) .build(); } @Bean public TokenWebClientFilter tokenWebClientFilter() { return new TokenWebClientFilter(); } }
二、RestTemplate 对应拦截方案:ClientHttpRequestInterceptor
如果使用传统同步HTTP客户端RestTemplate,可通过ClientHttpRequestInterceptor实现请求拦截,功能与Feign.RequestInterceptor一致。实现示例如下:
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.HttpRequest; import org.springframework.http.client.ClientHttpRequestExecution; import org.springframework.http.client.ClientHttpRequestInterceptor; import org.springframework.http.client.ClientHttpResponse; import org.springframework.web.context.request.RequestAttributes; import org.springframework.web.context.request.RequestContextHolder; import java.io.IOException; import java.util.UUID; public class TokenRestTemplateInterceptor implements ClientHttpRequestInterceptor { private static final Logger LOG = LoggerFactory.getLogger(TokenRestTemplateInterceptor.class); public static final String TOKEN_HEADER_NAME = "my-token"; @Override public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException { String traceToken = computeTraceTokenIfAbsent(); request.getHeaders().add(TOKEN_HEADER_NAME, traceToken); return execution.execute(request, body); } private String computeTraceTokenIfAbsent() { try { var attribute = RequestContextHolder.currentRequestAttributes() .getAttribute(TOKEN_HEADER_NAME, RequestAttributes.SCOPE_REQUEST); if (attribute instanceof String strAttribute) { RequestContextHolder.currentRequestAttributes() .setAttribute(TOKEN_HEADER_NAME, strAttribute, RequestAttributes.SCOPE_REQUEST); return strAttribute; } } catch (IllegalStateException e) { LOG.debug("Not in a request context: Creating new token for outgoing request.", e); } return UUID.randomUUID().toString(); } }
配置RestTemplate时注册该拦截器:
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestTemplate; import java.util.Collections; @Configuration public class RestTemplateConfig { @Bean public RestTemplate restTemplate(TokenRestTemplateInterceptor tokenInterceptor) { RestTemplate restTemplate = new RestTemplate(); restTemplate.setInterceptors(Collections.singletonList(tokenInterceptor)); return restTemplate; } @Bean public TokenRestTemplateInterceptor tokenRestTemplateInterceptor() { return new TokenRestTemplateInterceptor(); } }
内容的提问来源于stack exchange,提问作者François Poirier
相关产品推荐
相关产品推荐

