av一区二区在线观看_亚洲男人的天堂网站_日韩亚洲视频_在线成人免费_欧美日韩精品免费观看视频_久草视

您的位置:首頁(yè)技術(shù)文章
文章詳情頁(yè)

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

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

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

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

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

想到是不是因?yàn)樾薷牧薭ody內(nèi)容導(dǎo)致的問(wèn)題,試著不修改body的內(nèi)容,直接傳給微服務(wù),果然沒(méi)有報(bào)錯(cuò)了。

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

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

這里要再次表?yè)P(yáng)一下古哥,同樣是中文文章,度娘卻搜不到

不過(guò)文章中的spring cloud版本是

Spring Cloud: Greenwich.RC2

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

下面給出我的代碼

網(wǎng)關(guān)中對(duì)body內(nèi)容進(jìn)行解密然后驗(yàn)簽

/** * @author tengdj * @date 2019/8/13 11:08 * 設(shè)備接口驗(yàn)簽,解密 **/@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)) { //重新構(gòu)造request,參考ModifyRequestBodyGatewayFilterFactory ServerRequest serverRequest = ServerRequest.create(exchange, HandlerStrategies.withDefaults().messageReaders()); MediaType mediaType = exchange.getRequest().getHeaders().getContentType(); //重點(diǎn) Mono<String> modifiedBody = serverRequest.bodyToMono(String.class).flatMap(body -> { //因?yàn)榧s定了終端傳參的格式,所以只考慮json的情況,如果是表單傳參,請(qǐng)自行發(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()); //猜測(cè)這個(gè)就是之前報(bào)400錯(cuò)誤的元兇,之前修改了body但是沒(méi)有重新寫content length headers.remove('Content-Length'); //MyCachedBodyOutputMessage 這個(gè)類完全就是CachedBodyOutputMessage,只不過(guò)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 驗(yàn)簽 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('耗時(shí):{}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(); } }; }}

代碼到這里就結(jié)束了,希望看到的朋友可以少走點(diǎn)彎路,少踩點(diǎn)坑。

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

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

版本如下,請(qǐng)注意Springboot版本,這是本篇Post請(qǐng)求異常的關(guān)鍵。

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

1 對(duì)應(yīng)的uri只能是get請(qǐng)求

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

看一個(gè)簡(jiǎn)單的示例,addRequestParameter,我們匹配/addParam請(qǐng)求,并將請(qǐng)求轉(zhuǎn)發(fā)至http://localhost:8888/header

這個(gè)是8888端口的服務(wù)

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

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

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

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

注意,這里我用了PostMapping,然后分別啟動(dòng)兩個(gè)工程,再訪問(wèn)localhost:8080/addParam,而后會(huì)報(bào)錯(cuò),這個(gè)也可以理解。

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

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

但是事實(shí)上不是的

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

網(wǎng)關(guān)程序會(huì)報(bào)錯(cuò)如下:

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

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

經(jīng)過(guò)一番探索,發(fā)現(xiàn)這是Springboot不同版本的原因?qū)е拢赟pringboot2.0.5之前,不存在該問(wèn)題,之后就有這種問(wèn)題了。需要加以注意,解決方案會(huì)在下一篇寫。

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

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

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

這里,我將value的值變成帶空格的,然后去訪問(wèn)后端的服務(wù)。

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

然后會(huì)發(fā)現(xiàn)控制臺(tái)報(bào)錯(cuò),Invalid URI query。這是因?yàn)間et請(qǐng)求的value值不能含有非法字符.

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

同理

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

像這樣的,后臺(tái)接收的是

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

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

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

后臺(tái)這樣

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

結(jié)果是:

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

這樣就可以添加多個(gè)parameter了。

同時(shí)添加header和parameter

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

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

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

結(jié)果就只有header被打印了

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

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

貌似通過(guò)java代碼是無(wú)法實(shí)現(xiàn)了,好在可以通過(guò)yml配置來(lái)實(shí)現(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里,添加多個(gè)filter了,注意不要寫錯(cuò)了filter的名字。

可以看到結(jié)果

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

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

發(fā)現(xiàn)header和param都傳過(guò)來(lái)了。

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

標(biāo)簽: Spring
相關(guān)文章:
主站蜘蛛池模板: 欧美在线a| 欧美成人猛片aaaaaaa | 精品一区二区三区免费看 | 亚洲精品福利视频 | 激情五月综合 | 欧美va亚洲va | 久久久久久国产精品 | 久久一区二区视频 | 欧美在线观看一区 | 午夜网站在线观看 | 色香蕉网 | 日韩黄色大片 | 国产精品伦 | 日本理论片午伦夜理片在线观看 | 久久男人天堂 | 国产精品日韩欧美 | 亚洲精品自拍视频 | 欧美日韩亚洲另类 | 亚洲欧美在线观看 | 精品一区二区三区免费看 | 性做久久久久久久免费看 | 一本色道久久综合亚洲精品小说 | 国产精品成人一区二区三区 | 久久在线 | 黄色www| 欧美精品福利 | www黄色片 | 中文字幕精品在线观看 | 亚洲在线一区 | 欧美午夜精品 | 免费日韩视频 | 日本成人一区二区 | 久操精品 | 午夜美女福利 | 日韩成人中文字幕 | 国产人成一区二区三区影院 | 国产一区中文字幕 | 国产一区二区福利 | 午夜精品视频 | 亚洲高清免费视频 | www色|