欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

 更新時(shí)間:2020年12月01日 14:48:28   作者:seantdj  
這篇文章主要介紹了解決spring cloud gateway 獲取body內(nèi)容并修改的問題,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧

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

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

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

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

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

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

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

不過文章中的spring cloud版本是

Spring Cloud: Greenwich.RC2

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

下面給出我的代碼

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

/**
 * @author tengdj
 * @date 2019/8/13 11:08
 * 設(shè)備接口驗(yàn)簽,解密
 **/
@Slf4j
public 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的情況,如果是表單傳參,請自行發(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());
  //猜測這個(gè)就是之前報(bào)400錯(cuò)誤的元兇,之前修改了body但是沒有重新寫content length
  headers.remove("Content-Length");
  //MyCachedBodyOutputMessage 這個(gè)類完全就是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 驗(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ǔ)充知識:springcloud gateway之a(chǎn)ddRequestParameter詳細(xì)使用及踩坑注意

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

同理

像這樣的,后臺接收的是

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

后臺這樣

結(jié)果是:

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

同時(shí)添加header和parameter

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

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

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

貌似通過java代碼是無法實(shí)現(xiàn)了,好在可以通過yml配置來實(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é)果

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

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

相關(guān)文章

  • Activiti如何動(dòng)態(tài)獲取流程圖過程詳解

    Activiti如何動(dòng)態(tài)獲取流程圖過程詳解

    這篇文章主要介紹了Activiti如何動(dòng)態(tài)獲取流程圖過程詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-03-03
  • 深入了解Java設(shè)計(jì)模式之職責(zé)鏈模式

    深入了解Java設(shè)計(jì)模式之職責(zé)鏈模式

    Java設(shè)計(jì)模式中有很多種類別,例如單例模式、裝飾模式、觀察者模式等。本文將為大家詳細(xì)介紹其中的職責(zé)鏈模式,感興趣的可以了解一下
    2022-09-09
  • MybatisPlus多數(shù)據(jù)源及事務(wù)解決思路

    MybatisPlus多數(shù)據(jù)源及事務(wù)解決思路

    這篇文章主要介紹了MybatisPlus多數(shù)據(jù)源及事務(wù)解決思路,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-01-01
  • idea普通javaweb項(xiàng)目如何部署到tomcat(讀取web.xml文件)

    idea普通javaweb項(xiàng)目如何部署到tomcat(讀取web.xml文件)

    這篇文章主要介紹了idea普通javaweb項(xiàng)目如何部署到tomcat(讀取web.xml文件),具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • Mac系統(tǒng)搭建JDK及JMETER過程解析

    Mac系統(tǒng)搭建JDK及JMETER過程解析

    這篇文章主要介紹了Mac系統(tǒng)搭建JDK及JMETER過程解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-08-08
  • 基于Java事件監(jiān)聽編寫一個(gè)中秋猜燈謎小游戲

    基于Java事件監(jiān)聽編寫一個(gè)中秋猜燈謎小游戲

    眾所周知,JavaSwing是Java中關(guān)于窗口開發(fā)的一個(gè)工具包,可以開發(fā)一些窗口程序,然后由于工具包的一些限制,導(dǎo)致Java在窗口開發(fā)商并沒有太多優(yōu)勢,不過,在JavaSwing中關(guān)于事件的監(jiān)聽機(jī)制是我們需要重點(diǎn)掌握的內(nèi)容,本文將基于Java事件監(jiān)聽編寫一個(gè)中秋猜燈謎小游戲
    2023-09-09
  • Java畢業(yè)設(shè)計(jì)實(shí)戰(zhàn)之校園一卡通系統(tǒng)的實(shí)現(xiàn)

    Java畢業(yè)設(shè)計(jì)實(shí)戰(zhàn)之校園一卡通系統(tǒng)的實(shí)現(xiàn)

    這是一個(gè)使用了java+Springboot+Maven+mybatis+Vue+mysql+wd開發(fā)的校園一卡通系統(tǒng),是一個(gè)畢業(yè)設(shè)計(jì)的實(shí)戰(zhàn)練習(xí),具有校園一卡通系統(tǒng)該有的所有功能,感興趣的朋友快來看看吧
    2022-01-01
  • 解決java.util.NoSuchElementException異常正確方法

    解決java.util.NoSuchElementException異常正確方法

    java.util.NoSuchElementException是Java中的一種異常,表示在迭代器或枚舉中找不到元素,這篇文章主要給大家介紹了關(guān)于解決java.util.NoSuchElementException異常的相關(guān)資料,需要的朋友可以參考下
    2023-11-11
  • 必須詳細(xì)與全面的Java開發(fā)環(huán)境搭建圖文教程

    必須詳細(xì)與全面的Java開發(fā)環(huán)境搭建圖文教程

    本篇文章內(nèi)容包括:Linux理論與實(shí)操,MySQL實(shí)操,JDK實(shí)操,Tomcat實(shí)操和Tomcat實(shí)操,需要的朋友可以參考下
    2019-11-11
  • 使用Spring Cache和Redis實(shí)現(xiàn)查詢數(shù)據(jù)緩存

    使用Spring Cache和Redis實(shí)現(xiàn)查詢數(shù)據(jù)緩存

    在現(xiàn)代應(yīng)用程序中,查詢緩存的使用已經(jīng)變得越來越普遍,它不僅能夠顯著提高系統(tǒng)的性能,還能提升用戶體驗(yàn),在這篇文章中,我們將探討緩存的基本概念、重要性以及如何使用Spring Cache和Redis實(shí)現(xiàn)查詢數(shù)據(jù)緩存,需要的朋友可以參考下
    2024-07-07

最新評論