在 Spring boot web
中咱們能夠經過 RequestContextHolder
很方便的獲取 request
。vue
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); // 獲取 request HttpServletRequest request = requestAttributes.getRequest();
再也不須要經過參數傳遞 request
。在 Spring webflux 中並沒提供該功能,使得咱們在 Aop 或者一些其餘的場景中獲取 request
變成了一個奢望???java
首先我想到的是看看 spring-security
中是否有對於的解決方案,由於在 spring-security
中咱們也是能夠經過 SecurityContextHolder
很方便快捷的獲取當前登陸的用戶信息。react
找到了 ReactorContextWebFilter,咱們來看看 security 中他是怎麼實現的。
https://github.com/spring-pro...git
public class ReactorContextWebFilter implements WebFilter { private final ServerSecurityContextRepository repository; public ReactorContextWebFilter(ServerSecurityContextRepository repository) { Assert.notNull(repository, "repository cannot be null"); this.repository = repository; } @Override public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) { return chain.filter(exchange) .subscriberContext(c -> c.hasKey(SecurityContext.class) ? c : withSecurityContext(c, exchange) ); } private Context withSecurityContext(Context mainContext, ServerWebExchange exchange) { return mainContext.putAll(this.repository.load(exchange) .as(ReactiveSecurityContextHolder::withSecurityContext)); } }
源碼裏面咱們能夠看到 他利用一個 Filter,chain.filter(exchange)
的返回值 Mono 調用了 subscriberContext 方法。
那麼咱們就去了解一下這個 reactor.util.context.Context
。找到 reactor 官方文檔中的 context 章節:https://projectreactor.io/doc...github
大意是:從 Reactor 3.1.0 開始提供了一個高級功能,能夠與 ThreadLocal 媲美,應用於 Flux 和 Mono 的上下文工具 Context。更多請你們查閱官方文檔,對英文比較抵觸的朋友能夠使用 google 翻譯。web
mica 中的實現比較簡單,首先是咱們的 ReactiveRequestContextFilter
:spring
/** * ReactiveRequestContextFilter * * @author L.cm */ @Configuration @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE) public class ReactiveRequestContextFilter implements WebFilter { @Override public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) { ServerHttpRequest request = exchange.getRequest(); return chain.filter(exchange) .subscriberContext(ctx -> ctx.put(ReactiveRequestContextHolder.CONTEXT_KEY, request)); } }
在 Filter
中直接將 request
存儲到 Context
上下文中。架構
ReactiveRequestContextHolder 工具:app
/** * ReactiveRequestContextHolder * * @author L.cm */ public class ReactiveRequestContextHolder { static final Class<ServerHttpRequest> CONTEXT_KEY = ServerHttpRequest.class; /** * Gets the {@code Mono<ServerHttpRequest>} from Reactor {@link Context} * @return the {@code Mono<ServerHttpRequest>} */ public static Mono<ServerHttpRequest> getRequest() { return Mono.subscriberContext() .map(ctx -> ctx.get(CONTEXT_KEY)); } }
request
中獲取請求的相關信息@ExceptionHandler(Throwable.class) @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) public Mono<?> handleError(Throwable e) { log.error("未知異常", e); // 發送:未知異常異常事件 return ReactiveRequestContextHolder.getRequest() .doOnSuccess(r -> publishEvent(r, e)) .flatMap(r -> Mono.just(R.fail(SystemCode.FAILURE))); } private void publishEvent(ServerHttpRequest request, Throwable error) { // 具體業務邏輯 }
request
中的 header
此示例來源於開源中國問答中筆者的回覆: 《如何在gateway 中獲取 webflux的 RequestContextHolder》框架
@GetMapping("/test") @ResponseBody public Mono<String> test() { WebClient webClient = testClient(); return webClient.get().uri("").retrieve().bodyToMono(String.class); } @Bean public WebClient testClient() { return WebClient.builder() .filter(testFilterFunction()) .baseUrl("https://www.baidu.com") .build(); } private ExchangeFilterFunction testFilterFunction() { return (request, next) -> ReactiveRequestContextHolder.getRequest() .flatMap(r -> { ClientRequest clientRequest = ClientRequest.from(request) .headers(headers -> headers.set(HttpHeaders.USER_AGENT, r.getHeaders().getFirst(HttpHeaders.USER_AGENT))) .build(); return next.exchange(clientRequest); }); }
上段代碼是透傳 web 中的 request
中的 user_agent
請求頭到 WebClient
中。
mica
Spring boot 微服務核心組件集:https://gitee.com/596392912/mica Avue
一款基於vue可配置化的神奇框架:https://gitee.com/smallweigit/avue pig
宇宙最強微服務(架構師必備):https://gitee.com/log4j/pig SpringBlade
完整的線上解決方案(企業開發必備):https://gitee.com/smallc/SpringBlade IJPay
支付SDK讓支付觸手可及:https://gitee.com/javen205/IJPay
掃描上面二維碼,更多精彩內容天天推薦!
如夢技術對此篇文章有最終全部權,轉載請註明出處,參考也請註明,謝謝!