日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術文章
文章詳情頁

Spring Cloud Gateway(讀取、修改 Request Body)的操作

瀏覽:165日期:2023-07-30 10:27:01

Spring Cloud Gateway(以下簡稱 SCG)做為網關服務,是其他各服務對外中轉站,通過 SCG 進行請求轉發。

在請求到達真正的微服務之前,我們可以在這里做一些預處理,比如:來源合法性檢測,權限校驗,反爬蟲之類…

因為業務需要,我們的服務的請求參數都是經過加密的。

之前是在各個微服務的攔截器里對來解密驗證的,現在既然有了網關,自然而然想把這一步驟放到網關層來統一解決。

Spring Cloud Gateway(讀取、修改 Request Body)的操作

如果是使用普通的 Web 編程中(比如用 Zuul),這本就是一個 pre filter 的事兒,把之前 Interceptor 中代碼搬過來稍微改改就 OK 了。

不過因為使用的 SCG,它基于 Spring 5 的 WebFlux,即 Reactor 編程,要讀取 Request Body 中的請求參數就沒那么容易了。

本篇內容涉及 WebFlux 的響應式編程及 SCG 自定義全局過濾器,如果對這兩者不了解的話,可以先看看相關的內容。

兩個大坑

我們先建一個 Filter 來看看

public class ValidateFilter implements GlobalFilter, Ordered { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { ServerHttpRequest request = exchange.getRequest(); HttpHeaders headers = request.getHeaders(); MultiValueMap<String, HttpCookie> cookies = request.getCookies(); MultiValueMap<String, String> queryParams = request.getQueryParams(); Flux<DataBuffer> body = request.getBody(); return null; } @Override public int getOrder() { return 0; }}

從上邊的返回值可以看出,如果是取 Header、Cookie、Query Params 都易如反掌,如果你需要校驗的數據在這三者之中的話,就沒必要往下看了。

說回 Body,這里是一個Flux<DataBuffer>,即一個包含 0-N 個DataBuffer類型元素的異步序列。

首先不考慮 Request Body 只能讀取一次問題(這個問題可以用緩存解決),我們先來把這個 Flux 轉化成我們可以處理的字符串,第一反應想到的有兩個辦法:

block() 異步變同步

subscribe() 訂閱并觸發序列

BUT,理想很豐滿,現實卻很骨感——這兩個辦法都有問題:

WebFlux 中不能使用阻塞的操作

java.lang.IllegalStateException: block()/blockFirst()/blockLast() are blocking, which is not supported in thread reactor-http-server-epoll-7

subscribe() 只會接收到第一個發出的元素,所以會導致獲取不全的問題(太長的 Body 會被截斷)。這個問題網上有人用 AtomicReference<String> 來包裝獲取到字符串,有人用 StringBuilder/StringBuffer

以上兩個問題在網上找了半天,也沒找到一個靠譜的解決辦法,都是人云亦云。特別是第二個問題的所謂的“解決辦法”,大家無非就在是不遺余力的在展示 DataBuffer 轉 String 的 N 種寫法,而沒有從根本上解決被截斷的問題。

正確姿勢

2019.08.26 更新:

評論里有網友提醒到 Spring Cloud Gateway 2.1.2 下 DefaultServerRequest、CachedBodyOutputMessage 類的訪問權限已經改了。這一塊我看了一下,源碼確實改動了一些,不過 DefaultServerRequest 這個類已經不需要了,而 CachedBodyOutputMessage 類我們可以模(chao)仿(xi)它的實現。

其實這里的實現不管再怎么變,我們只要死盯著 ModifyRequestBodyGatewayFilterFactory 就行了。即使以后這里邊的相關類的訪問權限都改成 Default 了,我們也不用一個個去抄一遍,只要在org.springframework.cloud.gateway.filter.factory.rewrite 這個 package 下寫我們自己的類就好了。

Spring Cloud Gateway(讀取、修改 Request Body)的操作

———? 分割線 ———-

最終找到解決方案還是通過研讀 SCG 的源碼。

本文使用的版本:

Spring Cloud: Greenwich.RC2

Spring Boot: 2.1.1.RELEASE

在 org.springframework.cloud.gateway.filter.factory.rewrite 包下有個 ModifyRequestBodyGatewayFilterFactory,顧名思義,這就是修改 Request Body 的過濾器工廠類。

但是這個類我們無法直接使用,因為要用的話這個 FilterFactory 只能用 Fluent API 的方式配置,而無法在配置文件中使用,類似于這樣

.route('rewrite_request_upper', r -> r.host('*.rewriterequestupper.org') .filters(f -> f.prefixPath('/httpbin') .addResponseHeader('X-TestHeader', 'rewrite_request_upper') .modifyRequestBody(String.class, String.class, (exchange, s) -> { return Mono.just(s.toUpperCase()+s.toUpperCase()); }) ).uri(uri))

我更喜歡用配置文件來配置路由,所以這種方式并不是我的菜。

這時候我就需要自己弄一個 GlobalFilter 了。既然官方已經提供了“葫蘆”,那么我們就畫個“瓢”吧。

如果了解的 GatewayFilterFactory 和 GatewayFilter 的關系的話,不用我說你就知道該怎么辦了。不知道也沒關系,我們把 ModifyRequestBodyGatewayFilterFactory 中紅框部分 copy 出來,粘貼到我們之前創建的 ValidateFilter#filter 中

Spring Cloud Gateway(讀取、修改 Request Body)的操作

我們稍作修改,即可實現讀取并修改 Request Body 的功能了(核心部分見上圖黃色箭頭處)

/** * @author yibo */public class ValidateFilter implements GlobalFilter, Ordered { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { ServerRequest serverRequest = new DefaultServerRequest(exchange); // mediaType MediaType mediaType = exchange.getRequest().getHeaders().getContentType(); // read & modify body Mono<String> modifiedBody = serverRequest.bodyToMono(String.class) .flatMap(body -> { if (MediaType.APPLICATION_FORM_URLENCODED.isCompatibleWith(mediaType)) { // origin body map Map<String, Object> bodyMap = decodeBody(body); // TODO decrypt & auth // new body map Map<String, Object> newBodyMap = new HashMap<>(); return Mono.just(encodeBody(newBodyMap)); } return Mono.empty(); }); BodyInserter bodyInserter = BodyInserters.fromPublisher(modifiedBody, String.class); HttpHeaders headers = new HttpHeaders(); headers.putAll(exchange.getRequest().getHeaders()); // the new content type will be computed by bodyInserter // and then set in the request decorator headers.remove(HttpHeaders.CONTENT_LENGTH); CachedBodyOutputMessage outputMessage = new CachedBodyOutputMessage(exchange, headers); return bodyInserter.insert(outputMessage, new BodyInserterContext()) .then(Mono.defer(() -> { ServerHttpRequestDecorator decorator = new ServerHttpRequestDecorator( exchange.getRequest()) { @Override public HttpHeaders getHeaders() { long contentLength = headers.getContentLength(); HttpHeaders httpHeaders = new HttpHeaders(); httpHeaders.putAll(super.getHeaders()); if (contentLength > 0) {httpHeaders.setContentLength(contentLength); } else {httpHeaders.set(HttpHeaders.TRANSFER_ENCODING, 'chunked'); } return httpHeaders; } @Override public Flux<DataBuffer> getBody() { return outputMessage.getBody(); } }; return chain.filter(exchange.mutate().request(decorator).build()); })); } @Override public int getOrder() { return 0; } private Map<String, Object> decodeBody(String body) { return Arrays.stream(body.split('&')) .map(s -> s.split('=')) .collect(Collectors.toMap(arr -> arr[0], arr -> arr[1])); } private String encodeBody(Map<String, Object> map) { return map.entrySet().stream().map(e -> e.getKey() + '=' + e.getValue()).collect(Collectors.joining('&')); }}

至于拿到 Body 后具體要做什么,也就上邊代碼中的TODO部分,就由你自己來發揮吧~ 別玩壞就好

建議大家可以多關注關注 SCG 的源碼,說不定什么時候就會多出一些有用的 Filter 或 FilterFactory。

另外,目前 ModifyRequestBodyGatewayFilterFactory 上的 Javadoc 有這么一句話:

This filter is BETA and may be subject to change in a future release.

所以大家要保持關注呀~

以上這篇Spring Cloud Gateway(讀取、修改 Request Body)的操作就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支持好吧啦網。

標簽: Spring
相關文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
欧美搞黄网站| 国产亚洲精品久久久久婷婷瑜伽| 亚洲免费精品| 国产高清一区| 蜜桃视频免费观看一区| 91在线成人| 无码日韩精品一区二区免费| 亚洲一级网站| 欧美二区视频| 不卡中文一二三区| 日韩免费福利视频| 日韩理论片av| 欧美午夜精彩| 红桃视频国产一区| 亚洲国产日韩欧美在线| 91久久久精品国产| 99日韩精品| 爽好多水快深点欧美视频| 蜜臀久久久久久久| 日韩高清在线不卡| 国产精品美女午夜爽爽| 美女久久久久久 | 亚洲资源网站| 亚洲毛片网站| 91精品麻豆| 国产精品最新| 午夜久久中文| 日韩午夜高潮| 色狠狠一区二区三区| 欧美日韩一区自拍| 美女视频网站久久| 国产h片在线观看| 国产一区亚洲| 一区二区三区午夜视频| 7777精品| 久久伊人久久| 成人羞羞视频播放网站| 久久精品观看| 三级欧美在线一区| 国产欧美欧美| 日韩大片免费观看| 欧美另类专区| 日本aⅴ精品一区二区三区 | 日韩av首页| 午夜亚洲精品| 国产日韩在线观看视频| 精品一区二区三区中文字幕在线| 久久久一二三| 免费视频一区三区| 日韩成人一级| 成人啊v在线| 蜜臀久久99精品久久久画质超高清 | 亚洲特色特黄| 一区二区高清| 麻豆传媒一区二区三区| 999国产精品| 日韩精彩视频在线观看| 久久久国产精品入口麻豆| 欧洲在线一区| 91精品在线免费视频| 国产精久久一区二区| 色婷婷精品视频| 婷婷综合国产| 久久久久久黄| 欧美自拍一区| 日韩av一级| 久久国产人妖系列| 欧美日韩第一| 久久久久久亚洲精品美女| 国产亚洲精品v| 成人在线视频区| 中文字幕一区二区三区四区久久| 国产精品欧美日韩一区| 91精品电影| 麻豆一区二区在线| 99视频精品| 精品一区二区三区在线观看视频 | 久久久久中文| 国产欧美高清| 日韩午夜在线| 成人在线视频免费| 日本一区二区中文字幕| 都市激情国产精品| 亚洲伊人影院| 亚洲va中文在线播放免费| 久久精品99久久久| 亚洲精华国产欧美| 日本蜜桃在线观看视频| 久久国际精品| 爽爽淫人综合网网站| 亚洲二区视频| 久久久久久夜| 牛牛精品成人免费视频| 日本中文字幕一区二区| 亚洲激情偷拍| 亚洲天堂黄色| 欧美精选视频一区二区| 狠狠久久伊人| 国产日韩中文在线中文字幕 | 蜜桃免费网站一区二区三区| 欧美sm一区| 另类小说一区二区三区| 日韩精品欧美精品| 天堂va蜜桃一区二区三区| 亚洲特级毛片| 久久国产免费| 给我免费播放日韩视频| 国产精品v日韩精品v欧美精品网站| 午夜精品网站| 亚洲va在线| 国产成人免费| 亚洲v天堂v手机在线| 婷婷综合亚洲| 九九精品调教| 国产精品一区二区中文字幕| 国产毛片久久| 日韩一区二区久久| 精品成人免费一区二区在线播放| 久草免费在线视频| 国产精品日韩精品在线播放| 91欧美极品| 中文字幕日韩亚洲| 免费在线观看日韩欧美| 日韩在线中文| 亚洲精品永久免费视频| 国产精品黄色片| 国产午夜一区| 日本国产一区| 日本三级亚洲精品| 亚洲日本国产| 日韩高清不卡在线| 国产精品毛片| 合欧美一区二区三区| 91偷拍一区二区三区精品| 国产在线视频欧美一区| 国产欧美日韩在线一区二区| 91精品国产自产精品男人的天堂| 亚洲一区二区三区高清不卡| 欧美另类综合| 成人台湾亚洲精品一区二区| 国精品产品一区| 国产精品午夜一区二区三区| 国产精品毛片久久久| 久久国产88| 爽爽淫人综合网网站| 综合亚洲视频| 蜜桃视频一区二区三区| 日韩av资源网| 欧美亚洲三级| 久久久久久久久成人| 欧美激情视频一区二区三区在线播放| 精品国产鲁一鲁****| 精品一区二区三区视频在线播放| 欧美激情一区| 精品一区二区三区的国产在线观看| 国产黄大片在线观看| 福利精品一区| 亚洲精品成人| 亚洲欧美激情诱惑| 人人爱人人干婷婷丁香亚洲| 日韩精品福利一区二区三区| 国产精品s色| 精品国产一区二区三区噜噜噜| 色综合www| 成人羞羞在线观看网站| 美女久久一区| 蜜桃视频在线观看一区二区| 国产精品一区高清| 美女久久久久久 | 国产中文字幕一区二区三区| 正在播放日韩精品| 日韩免费小视频| 欧洲激情综合| 中文字幕亚洲影视| 国产福利资源一区| 国产精品多人| 国产99久久久国产精品成人免费| 亚洲激情中文在线| 国产精品亚洲片在线播放| 欧美一区自拍| 中文在线免费视频| 亚洲一级影院| 91欧美精品| 岛国精品一区| 久久亚洲色图| 欧美不卡在线| 91九色综合| 亚洲性视频h| 日韩av一区二区三区| 日本国产精品| 最新国产精品| 91精品韩国| 亚洲区欧美区| 色老板在线视频一区二区| 欧美 日韩 国产一区二区在线视频 | 亚洲精品乱码| 美女av在线免费看| 亚洲专区欧美专区| 精品一区视频| 日韩一级欧洲|