在構建微服務架構時,Spring Cloud Gateway作為一個重要的微服務網關,經常需要在過濾器(Filter)中對POST請求的Body內容進行操作,如日志記錄、簽名驗證和權限驗證等。然而,由于Request的Body只能讀取一次,如果直接在過濾器中讀取而不進行封裝,可能導致后續服務無法獲取數據。
網上搜這個問題的解決方案,大多數文章都是告訴你寫一個Filter將Request的Body緩存起來。這種方法確實可以,只不過需要對代碼經過充分壓力測試,否則很有可能出現如下所示的堆外內存溢出問題。
reactorty.ReactorNetty$InternalNettyException: ioty.util.internal.OutOfDirectMemoryError:failed to allocate
實際上,Spring Cloud Gateway已經內置了AdaptCachedBodyGlobalFilter過濾器,它在Exchange中巧妙地緩存了Request的Body,避免了直接讀取導致的一系列問題。這種方式更為穩妥,避免了潛在的內存溢出風險。
圖片
在需要獲取Body的地方,我們只需要通過以下方法即可:
DataBuffer body = exchange.getAttributeOrDefault("cachedRequestBody", null);String bodyStr = body.toString(StandardCharsets.UTF_8);
只不過通過源碼可以看出,緩存RequestBody需要路由被標記為需要緩存,也就是this.routesToCache.containsKey(rouceId)方法必須返回true。
AdaptCachedBodyGlobalFilter會監聽EnableBodyCachingEvent事件,當發布該事件時就將RouteId放入routesToCache中。為了方便使用,我們可以編寫一個配置類,在初始化時發布EnableBodyCachingEvent事件,將所有路由都啟用緩存功能。
@Configuration(proxyBeanMethods = false)@Slf4jpublic class EnableCachedBodyConfiguration { @Resource private ApplicationEventPublisher publisher; @Resource private GatewayProperties gatewayProperties; @PostConstruct public void init() { gatewayProperties.getRoutes().forEach(routeDefinition -> { // 對 spring cloud gateway 路由配置中的每個路由都啟用 AdaptCachedBodyGlobalFilter EnableBodyCachingEvent enableBodyCachingEvent = new EnableBodyCachingEvent(new Object(), routeDefinition.getId()); publisher.publishEvent(enableBodyCachingEvent); }); }}
通過這種方式,我們可以更加方便地處理POST請求的Body內容,避免了一些常見的問題。在實際應用中,考慮到穩定性和性能,這種解決方案提供了一種更為可靠的選擇。
本文鏈接:http://www.www897cc.com/showinfo-26-34565-0.html徹底解決Spring Cloud Gateway中Body讀取問題
聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com
上一篇: 優雅實現API接口開關:讓你的應用更可控