色综合图-色综合图片-色综合图片二区150p-色综合图区-玖玖国产精品视频-玖玖香蕉视频

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

解決spring cloud gateway 獲取body內(nèi)容并修改的問題

瀏覽:20日期:2023-07-30 09:53:58

之前寫過一篇文章,如何獲取body的內(nèi)容。

Spring Cloud Gateway獲取body內(nèi)容,不影響GET請求

確實能夠獲取所有body的內(nèi)容了,不過今天終端同學調(diào)試接口的時候和我說,遇到了400的問題,報錯是這樣的HTTP method names must be tokens,搜了一下,都是說https引起的。可我的項目還沒用https,排除了。

想到是不是因為修改了body內(nèi)容導致的問題,試著不修改body的內(nèi)容,直接傳給微服務,果然沒有報錯了。

問題找到,那就好辦了,肯定是我新構建的REQUEST對象缺胳膊少腿了,搜索一通之后發(fā)現(xiàn)一篇大牛寫的文章:

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

這里要再次表揚一下古哥,同樣是中文文章,度娘卻搜不到

不過文章中的spring cloud版本是

Spring Cloud: Greenwich.RC2

我本地是最新的Release版本RS3,并不能完全照搬過來,不過算是給了很大的啟發(fā)(如何獲取body以及重構)

下面給出我的代碼

網(wǎng)關中對body內(nèi)容進行解密然后驗簽

/** * @author tengdj * @date 2019/8/13 11:08 * 設備接口驗簽,解密 **/@Slf4jpublic class TerminalSignFilter implements GatewayFilter, Ordered { private static final String AES_SECURTY = 'XXX'; private static final String MD5_SALT = 'XXX'; @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { exchange.getAttributes().put('startTime', System.currentTimeMillis()); if (exchange.getRequest().getMethod().equals(HttpMethod.POST)) { //重新構造request,參考ModifyRequestBodyGatewayFilterFactory ServerRequest serverRequest = ServerRequest.create(exchange, HandlerStrategies.withDefaults().messageReaders()); MediaType mediaType = exchange.getRequest().getHeaders().getContentType(); //重點 Mono<String> modifiedBody = serverRequest.bodyToMono(String.class).flatMap(body -> { //因為約定了終端傳參的格式,所以只考慮json的情況,如果是表單傳參,請自行發(fā)揮 if (MediaType.APPLICATION_JSON.isCompatibleWith(mediaType) || MediaType.APPLICATION_JSON_UTF8.isCompatibleWith(mediaType)) { JSONObject jsonObject = JSONUtil.toJO(body); String paramStr = jsonObject.getString('param'); String newBody; try{ newBody = verifySignature(paramStr); }catch (Exception e){ return processError(e.getMessage()); } return Mono.just(newBody); } return Mono.empty(); }); BodyInserter bodyInserter = BodyInserters.fromPublisher(modifiedBody, String.class); HttpHeaders headers = new HttpHeaders(); headers.putAll(exchange.getRequest().getHeaders()); //猜測這個就是之前報400錯誤的元兇,之前修改了body但是沒有重新寫content length headers.remove('Content-Length'); //MyCachedBodyOutputMessage 這個類完全就是CachedBodyOutputMessage,只不過CachedBodyOutputMessage不是公共的 MyCachedBodyOutputMessage outputMessage = new MyCachedBodyOutputMessage(exchange, headers); return bodyInserter.insert(outputMessage, new BodyInserterContext()).then(Mono.defer(() -> { ServerHttpRequest decorator = this.decorate(exchange, headers, outputMessage); return returnMono(chain, exchange.mutate().request(decorator).build()); })); } else { //GET 驗簽 MultiValueMap<String, String> map = exchange.getRequest().getQueryParams(); if (!CollectionUtils.isEmpty(map)) { String paramStr = map.getFirst('param'); try{ verifySignature(paramStr); }catch (Exception e){ return processError(e.getMessage()); } } return returnMono(chain, exchange); } } @Override public int getOrder() { return 1; } private Mono<Void> returnMono(GatewayFilterChain chain,ServerWebExchange exchange){ return chain.filter(exchange).then(Mono.fromRunnable(()->{ Long startTime = exchange.getAttribute('startTime'); if (startTime != null){ long executeTime = (System.currentTimeMillis() - startTime); log.info('耗時:{}ms' , executeTime); log.info('狀態(tài)碼:{}' , Objects.requireNonNull(exchange.getResponse().getStatusCode()).value()); } })); } private String verifySignature(String paramStr) throws Exception{ log.info('密文{}', paramStr); String dParamStr; try{ dParamStr = AESUtil.decrypt(paramStr, AES_SECURTY); }catch (Exception e){ throw new Exception('解密失敗!'); } log.info('解密得到字符串{}', dParamStr); String signature = SignUtil.sign(dParamStr, MD5_SALT); log.info('重新加密得到簽名{}', signature); JSONObject jsonObject1 = JSONUtil.toJO(dParamStr); if (!jsonObject1.getString('signature').equals(signature)) { throw new Exception('簽名不匹配!'); } return jsonObject1.toJSONString(); } private Mono processError(String message) { /*exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED); return exchange.getResponse().setComplete();*/ log.error(message); return Mono.error(new Exception(message)); } ServerHttpRequestDecorator decorate(ServerWebExchange exchange, HttpHeaders headers, MyCachedBodyOutputMessage outputMessage) { return new ServerHttpRequestDecorator(exchange.getRequest()) { public HttpHeaders getHeaders() { long contentLength = headers.getContentLength(); HttpHeaders httpHeaders = new HttpHeaders(); httpHeaders.putAll(super.getHeaders()); if (contentLength > 0L) { httpHeaders.setContentLength(contentLength); } else { httpHeaders.set('Transfer-Encoding', 'chunked'); } return httpHeaders; } public Flux<DataBuffer> getBody() { return outputMessage.getBody(); } }; }}

代碼到這里就結束了,希望看到的朋友可以少走點彎路,少踩點坑。

補充知識:springcloud gateway之a(chǎn)ddRequestParameter詳細使用及踩坑注意

SpringCloud的網(wǎng)關gateway提供了多個內(nèi)置Filter,其中addRequestHeader是添加header的,這個無坑,比較簡單。還有一個添加參數(shù)的,addRequestParameter,這個就有點問題了。具體往下看。

版本如下,請注意Springboot版本,這是本篇Post請求異常的關鍵。

解決spring cloud gateway 獲取body內(nèi)容并修改的問題

1 對應的uri只能是get請求

解決spring cloud gateway 獲取body內(nèi)容并修改的問題

看一個簡單的示例,addRequestParameter,我們匹配/addParam請求,并將請求轉發(fā)至http://localhost:8888/header

這個是8888端口的服務

解決spring cloud gateway 獲取body內(nèi)容并修改的問題

如果發(fā)起Get請求到網(wǎng)關,那么可以正常請求,一切OK。此時,調(diào)用發(fā)起方和最終的服務提供方都是Get請求,沒有問題。

如果發(fā)起的請求是Get,但是服務提供方是如下的Post。

解決spring cloud gateway 獲取body內(nèi)容并修改的問題

注意,這里我用了PostMapping,然后分別啟動兩個工程,再訪問localhost:8080/addParam,而后會報錯,這個也可以理解。

解決spring cloud gateway 獲取body內(nèi)容并修改的問題

但是,如果調(diào)用發(fā)起方和服務提供方都是Post請求,理論上應該也是OK的。

但是事實上不是的

解決spring cloud gateway 獲取body內(nèi)容并修改的問題

網(wǎng)關程序會報錯如下:

解決spring cloud gateway 獲取body內(nèi)容并修改的問題

這個就很尷尬了,作為一個網(wǎng)關,居然在代理非Get請求時出現(xiàn)異常,必然是不能容忍的。

經(jīng)過一番探索,發(fā)現(xiàn)這是Springboot不同版本的原因導致,在Springboot2.0.5之前,不存在該問題,之后就有這種問題了。需要加以注意,解決方案會在下一篇寫。

2 添加的參數(shù)value值必須合法(不能含有空格)

解決spring cloud gateway 獲取body內(nèi)容并修改的問題

上面已經(jīng)知道了,addRequestParameter對應的后端請求是Get型,那么明顯添加的parameter只能是Get請求支持的,能在瀏覽器地址欄直接敲上去合法的。

這里,我將value的值變成帶空格的,然后去訪問后端的服務。

解決spring cloud gateway 獲取body內(nèi)容并修改的問題

然后會發(fā)現(xiàn)控制臺報錯,Invalid URI query。這是因為get請求的value值不能含有非法字符.

解決spring cloud gateway 獲取body內(nèi)容并修改的問題

同理

解決spring cloud gateway 獲取body內(nèi)容并修改的問題

像這樣的,后臺接收的是

解決spring cloud gateway 獲取body內(nèi)容并修改的問題

如果是這樣的參數(shù)

解決spring cloud gateway 獲取body內(nèi)容并修改的問題

后臺這樣

解決spring cloud gateway 獲取body內(nèi)容并修改的問題

結果是:

解決spring cloud gateway 獲取body內(nèi)容并修改的問題

這樣就可以添加多個parameter了。

同時添加header和parameter

結束了addRequestParameter的說明,我們可以來看看,假如某個path,既想addHeader,又想addParameter,而系統(tǒng)的這兩個方法,都是一個path只能搭配一個add的filter,即便寫了兩個也不生效,如

解決spring cloud gateway 獲取body內(nèi)容并修改的問題

解決spring cloud gateway 獲取body內(nèi)容并修改的問題

結果就只有header被打印了

解決spring cloud gateway 獲取body內(nèi)容并修改的問題

那么就是想同時添加header和parameter該怎么辦呢。

貌似通過java代碼是無法實現(xiàn)了,好在可以通過yml配置來實現(xiàn)。

spring: cloud: gateway: routes: - id: header uri: http://localhost:8888/header filters: - AddRequestHeader=NewHeader, Bar - AddRequestParameter=NewParam, Param predicates: - Path=/header

在yml就可以在filters里,添加多個filter了,注意不要寫錯了filter的名字。

可以看到結果

解決spring cloud gateway 獲取body內(nèi)容并修改的問題

解決spring cloud gateway 獲取body內(nèi)容并修改的問題

發(fā)現(xiàn)header和param都傳過來了。

以上這篇解決spring cloud gateway 獲取body內(nèi)容并修改的問題就是小編分享給大家的全部內(nèi)容了,希望能給大家一個參考,也希望大家多多支持好吧啦網(wǎng)。

標簽: Spring
相關文章:
主站蜘蛛池模板: 欧美老妇免费做爰视频 | 国产精品二区页在线播放 | 欧美国产精品亚洲精品第一区 | 国产精品久久久久久免费播放 | 在线看欧美日韩中文字幕 | 国产日韩欧美一区二区三区在线 | 亚洲欧美成人影院 | 亚洲成人精品久久 | 欧美一级欧美三级在线观看 | 欧美成人看片一区二区三区 | 6080伦理久久亚洲精品 | 日韩性黄色一级 | 久久久久亚洲精品一区二区三区 | 精品成人在线 | 亚洲免费国产 | 手机在线播放视频 | 欧美日韩国产一区二区三区在线观看 | 老司机精品福利视频 | 韩国日本三级在线观看 | 日本黄色大片免费观看 | 亚洲人成片在线观看 | 久久性生大片免费观看性 | 日韩三级影院 | 欧美成人性毛片免费版 | 精品午夜寂寞影院在线观看 | 久久精品久久久 | 国产精品一区在线播放 | 国产一区欧美二区 | 一级毛片在线免费看 | 19+韩国主播青草vip视频 | 国产男女视频 | 普通话对白国产精品一级毛片 | 久久久久日韩精品无 | 亚洲第一黄色网 | 亚洲炮网 | 国内久久精品 | 午夜影院啪啪 | 91精品综合久久久久m3u8 | 在线91精品国产免费 | 精品国产一区二区三区在线观看 | 国产激情一区二区三区 |