如何在Spring WebFlux的任何地方獲取Request對象
1 不一樣的世界
在常規(guī)的Spring Web項(xiàng)目中,我們要獲取Request對象是非常方便的,不少庫都提供了靜態(tài)方法來獲取。獲取代碼如下:
ServletRequestAttributes requestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes(); // get the request HttpServletRequest request = requestAttributes.getRequest();
在類RequestContextHolder提供了靜態(tài)方法,也就意味著你可以在任何地方調(diào)用。而它使用了ThreadLocal來保存Request對象,也就是不同線程是可以獲取各自的Request對象。
但在響應(yīng)式WebFlux的世界里,并沒有提供類似的Holder類,而WebFlux是無法感知線程的,任何一個線程可以在任何時候處理任何請求,如果它覺得切換當(dāng)前線程更有效率,它就會這么做。但在Servlet Based的應(yīng)用里,它會為某個請求安排一個線程去處理完整個過程。
這個巨大的差別,意味著不能簡單地通過ThreadLocal來保存和獲取Request了。
2 先保存,再獲取
為了在后面可以方便獲得Request對象,我們就需要在開始的時候把它存在一個可以使用、并且是相同scope的容器里。這里需要解決兩個關(guān)鍵問題:
(1)Request對象從何而來;
(2)存在哪里?
針對問題(1), 我們可以回想什么時候會出現(xiàn)Request對象,最容易想得到的就是WebFilter了,它的方法簽名如下:
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain);
我們可以通過ServerWebExchange直接獲取到Request對象:
ServerHttpRequest request = exchange.getRequest();
而因?yàn)?code>Filter是可以先于應(yīng)用邏輯執(zhí)行的,所以滿足要求,問題(1)解決。
針對問題(2),需要一個與Reavtive請求相同范圍的容器,reactor.util.context.Context可以滿足需求。查看reactor的官方文檔(https://projectreactor.io/docs/core/release/reference/#context )可見下面這段話:
Since version 3.1.0, Reactor comes with an advanced feature that is somewhat comparable to ThreadLocal but can be applied to a Flux or a Mono instead of a Thread. This feature is called Context.
并且官網(wǎng)也給出了為何ThreadLocal在某些場景不適用的解釋,有興趣可以看看。
3 代碼實(shí)現(xiàn)
3.1 WebFilter獲取并保存
首先,在WebFilter中獲取Request對象并保存,代碼如下:
@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));
}
}
從ServerWebExchange中獲取到ServerHttpRequest對象,再通過put方法把它放進(jìn)Context里。
3.2 工具類Holder
實(shí)現(xiàn)一個工具類來提供靜態(tài)方法,在Filter后的任何場景都可以使用:
public class ReactiveRequestContextHolder {
public static final Class<ServerHttpRequest> CONTEXT_KEY = ServerHttpRequest.class;
public static Mono<ServerHttpRequest> getRequest() {
return Mono.subscriberContext()
.map(ctx -> ctx.get(CONTEXT_KEY));
}
}
3.3 在Controller中使用
我們嘗試在Controller中使用ReactiveRequestContextHolder來獲取Request:
@RestController
public class GetRequestController {
@RequestMapping("/request")
public Mono<String> getRequest() {
return ReactiveRequestContextHolder.getRequest()
.map(request -> request.getHeaders().getFirst("user"));
}
}
上面方法獲取了Request對象,然后再獲取了Request中的Header。
啟動應(yīng)用,測試如下:
$ curl http://localhost:8088/request -H 'user: pkslow' pkslow $ curl http://localhost:8088/request -H 'user: larry' larry $ curl http://localhost:8088/request -H 'user: www.pkslow.com' www.pkslow.com
可以成功獲取請求頭user。
4 總結(jié)
代碼請查看:https://github.com/LarryDpk/pkslow-samples
以上就是如何在Spring WebFlux的任何地方獲取Request對象的詳細(xì)內(nèi)容,更多關(guān)于Spring WebFlux獲取Request對象的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java運(yùn)算符解密之位運(yùn)算、移位運(yùn)算舉例詳解
這篇文章主要介紹了Java運(yùn)算符解密之位運(yùn)算、移位運(yùn)算的相關(guān)資料,Java中的位運(yùn)算符包括按位與&、按位或|、按位取反~和按位異或^,用于對數(shù)據(jù)的二進(jìn)制位進(jìn)行操作,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2025-04-04
Java使用POI-TL和JFreeChart動態(tài)生成Word報告
本文介紹了使用POI-TL和JFreeChart生成包含動態(tài)數(shù)據(jù)和圖表的Word報告的方法,并分享了實(shí)際開發(fā)中的踩坑經(jīng)驗(yàn),通過代碼示例講解的非常詳細(xì),具有一定的參考價值,需要的朋友可以參考下2025-02-02
如何使用IDEA新建一個普通的Javaweb項(xiàng)目
今天給大家普及如何使用IDEA新建一個普通的Javaweb項(xiàng)目及配置tomcat的方法,在文末給大家提到如果不想每次都重啟tomcat,可以設(shè)置快捷方式,對idea新建Javaweb項(xiàng)目感興趣的朋友一起看看吧2021-06-06
springboot項(xiàng)目獲取resources相對路徑的方法
這篇文章主要介紹了springboot項(xiàng)目獲取resources相對路徑的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12
往DAO類中注入@PersistenceContext和@Resource的區(qū)別詳解
這篇文章主要介紹了往DAO類中注入@PersistenceContext和@Resource的區(qū)別詳解,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-02-02
關(guān)于SpringBoot改動后0.03秒啟動的問題
這篇文章主要介紹了SpringBoot改動后0.03秒啟動,本文結(jié)合示例代碼給大家講解的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-12-12
關(guān)于feign.codec.DecodeException異常的解決方案
這篇文章主要介紹了關(guān)于feign.codec.DecodeException異常的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-03-03

