范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

SpringCloudGateway修改请求和响应body的内容

  欢迎访问我的GitHub这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos本篇概览作为《Spring Cloud Gateway实战》系列的第九篇,咱们聊聊如何用Spring Cloud Gateway修改原始请求和响应内容,以及修改过程中遇到的问题首先是修改请求body,如下图,浏览器是请求发起方,真实参数只有user-id,经过网关时被塞入字段user-name,于是,后台服务收到的请求就带有user-name字段了
  其次是修改响应,如下图,服务提供方 provider-hello 的原始响应只有 response-tag 字段,经过网关时被塞入了 gateway-response-tag 字段,最终浏览器收到的响应就是 response-tag 和 gateway-response-tag 两个字段:
  总的来说,今天要做具体事情如下:准备工作:在服务提供者的代码中新增一个web接口,用于验证Gateway的操作是否有效介绍修改请求body和响应body的套路按套路开发一个过滤器(filter),用于修改请求的body按套路开发一个过滤器(filter),用于修改响应的body思考和尝试:如何从Gateway返回错误?在实战过程中,咱们顺便搞清楚两个问题:代码配置路由时,如何给一个路由添加多个filter?代码配置路由和yml配置是否可以混搭,两者有冲突吗?源码下载本篇实战中的完整源码可在GitHub下载到,地址和链接信息如下表所示(https://github.com/zq2599/blog_demos):
  这个git项目中有多个文件夹,本篇的源码在 spring-cloud-tutorials 文件夹下,如下图红框所示:
  spring-cloud-tutorials 文件夹下有多个子工程,本篇的代码是 gateway-change-body ,如下图红框所示:
  准备工作为了观察Gateway能否按预期去修改请求和响应的body,咱们给服务提供者 provider-hello 增加一个接口,代码在Hello.java中,如下:    @PostMapping("/change")     public Map change(@RequestBody Map map) {         map.put("response-tag", dateStr());         return map;     } 可见新增的web接口很简单:将收到的请求数据作为返回值,在里面添加了一个键值对,然后返回给请求方,有了这个接口,咱们就能通过观察返回值来判断Gateway对请求和响应的操作是否生效来试一下,先启动nacos(provider-hello需要的)再运行provider-hello应用,用Postman向其发请求试试,如下图,符合预期:
  准备工作已完成,开始开发吧 修改请求body的套路如何用Spring Cloud Gateway修改请求的body?来看看其中的套路:修改请求body是通过自定义filter实现的配置路由及其filter的时候,有yml配置文件和代码配置两种方式可以配置路由,官方文档给出的demo是代码配置的,因此今天咱们也参考官方做法,通过代码来配置路由和过滤器在代码配置路由的时候,调用filters方法,该方法的入参是个lambda表达式此lambda表达式固定调用modifyRequestBody方法,咱们只要定义好modifyRequestBody方法的三个入参即可modifyRequestBody方法的第一个入参是输入类型第二个入参是返回类型第三个是RewriteFunction接口的实现,这个代码需要您自己写,内容是将输入数据转换为返回类型数据具体逻辑,咱们来看官方Demo,也就是上述套路了:@Bean public RouteLocator routes(RouteLocatorBuilder builder) {     return builder.routes()         .route("rewrite_request_obj", r -> r.host("*.rewriterequestobj.org")             .filters(f -> f.prefixPath("/httpbin")                 .modifyRequestBody(String.class, Hello.class, MediaType.APPLICATION_JSON_VALUE,                     (exchange, s) -> return Mono.just(new Hello(s.toUpperCase())))).uri(uri))         .build(); }修改响应body的套路用Spring Cloud Gateway修改响应body的套路和前面的请求body如出一辙通过代码来配置路由和过滤器在代码配置路由的时候,调用filters方法,该方法的入参是个lambda表达式此lambda表达式固定调用modifyResponseBody方法,咱们只要定义好modifyResponseBody方法的三个入参即可modifyRequestBody方法的第一个入参是输入类型第二个入参是返回类型第三个是RewriteFunction接口的实现,这个代码要您自己写,内容是将输入数据转换为返回类型数据具体逻辑,咱们来看官方Demo,其实就是上述套路:@Bean public RouteLocator routes(RouteLocatorBuilder builder) {     return builder.routes()         .route("rewrite_response_upper", r -> r.host("*.rewriteresponseupper.org")             .filters(f -> f.prefixPath("/httpbin")                 .modifyResponseBody(String.class, String.class,                     (exchange, s) -> Mono.just(s.toUpperCase()))).uri(uri))         .build(); } 套路总结出来了,接下来,咱们一起撸代码? 按套路开发一个修改请求body的过滤器(filter)废话不说,在父工程spring-cloud-tutorials下新建子工程gateway-change-body,pom.xml无任何特殊之处,注意依赖spring-cloud-starter-gateway即可启动类毫无新意:package com.bolingcavalry.changebody;  import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;  @SpringBootApplication public class ChangeBodyApplication {     public static void main(String[] args) {         SpringApplication.run(ChangeBodyApplication.class,args);     } }配置文件千篇一律: server:   #服务端口   port: 8081 spring:   application:     name: gateway-change-body然后是核心逻辑:修改请求body的代码,既RewriteFunction的实现类,代码很简单,将原始的请求body解析成Map对象,取出user-id字段,生成user-name字段放回map,apply方法返回的是个Mono: package com.bolingcavalry.changebody.function;  import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; import org.reactivestreams.Publisher; import org.springframework.cloud.gateway.filter.factory.rewrite.RewriteFunction; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; import java.util.Map;   @Slf4j public class RequestBodyRewrite implements RewriteFunction {      private ObjectMapper objectMapper;      public RequestBodyRewrite(ObjectMapper objectMapper) {         this.objectMapper = objectMapper;     }      /**      * 根据用户ID获取用户名称的方法,可以按实际情况来内部实现,例如查库或缓存,或者远程调用      * @param userId      * @return      */     private  String mockUserName(int userId) {         return "user-" + userId;     }      @Override     public Publisher apply(ServerWebExchange exchange, String body) {         try {             Map map = objectMapper.readValue(body, Map.class);              // 取得id             int userId = (Integer)map.get("user-id");              // 得到nanme后写入map             map.put("user-name", mockUserName(userId));              // 添加一个key/value             map.put("gateway-request-tag", userId + "-" + System.currentTimeMillis());              return Mono.just(objectMapper.writeValueAsString(map));         } catch (Exception ex) {             log.error("1. json process fail", ex);             // json操作出现异常时的处理             return Mono.error(new Exception("1. json process fail", ex));         }     } }然后是按部就班的基于代码实现路由配置,重点是lambda表达式执行modifyRequestBody方法,并且将RequestBodyRewrite作为参数传入: package com.bolingcavalry.changebody.config;  import com.bolingcavalry.changebody.function.RequestBodyRewrite; import com.bolingcavalry.changebody.function.ResponseBodyRewrite; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.cloud.gateway.route.RouteLocator; import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.MediaType; import reactor.core.publisher.Mono;  @Configuration public class FilterConfig {     @Bean     public RouteLocator routes(RouteLocatorBuilder builder, ObjectMapper objectMapper) {         return builder                 .routes()                 .route("path_route_change",                         r -> r.path("/hello/change")                                 .filters(f -> f                                         .modifyRequestBody(String.class,String.class,new RequestBodyRewrite(objectMapper))                                         )                         .uri("http://127.0.0.1:8082"))                 .build();     } }代码写完了,运行工程 gateway-change-body ,在postman发起请求,得到响应如下图,红框中可见Gateway添加的内容已成功:
  现在修改请求body已经成功,接下来再来修改服务提供者响应的body 修改响应body接下来开发修改响应body的代码 新增RewriteFunction接口的实现类ResponseBodyRewrite.java package com.bolingcavalry.changebody.function;  import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; import org.reactivestreams.Publisher; import org.springframework.cloud.gateway.filter.factory.rewrite.RewriteFunction; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; import java.util.Map;  @Slf4j public class ResponseBodyRewrite implements RewriteFunction {      private ObjectMapper objectMapper;      public ResponseBodyRewrite(ObjectMapper objectMapper) {         this.objectMapper = objectMapper;     }      @Override     public Publisher apply(ServerWebExchange exchange, String body) {         try {             Map map = objectMapper.readValue(body, Map.class);              // 取得id             int userId = (Integer)map.get("user-id");              // 添加一个key/value             map.put("gateway-response-tag", userId + "-" + System.currentTimeMillis());              return Mono.just(objectMapper.writeValueAsString(map));         } catch (Exception ex) {             log.error("2. json process fail", ex);             return Mono.error(new Exception("2. json process fail", ex));         }     } }路由配置代码中,lambda表达式里面,filters方法内部调用modifyResponseBody,第三个入参是ResponseBodyRewrite: package com.bolingcavalry.changebody.config;  import com.bolingcavalry.changebody.function.RequestBodyRewrite; import com.bolingcavalry.changebody.function.ResponseBodyRewrite; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.cloud.gateway.route.RouteLocator; import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.MediaType; import reactor.core.publisher.Mono;  @Configuration public class FilterConfig {      @Bean     public RouteLocator routes(RouteLocatorBuilder builder, ObjectMapper objectMapper) {         return builder                 .routes()                 .route("path_route_change",                         r -> r.path("/hello/change")                                 .filters(f -> f                                         .modifyRequestBody(String.class,String.class,new RequestBodyRewrite(objectMapper))                                         .modifyResponseBody(String.class, String.class, new ResponseBodyRewrite(objectMapper))                                         )                         .uri("http://127.0.0.1:8082"))                 .build();     } }还记得咱们的第一个问题吗?通过上面的代码,您应该已经看到了答案:用代码配置路由时,多个过滤器的配置方法就是在filters方法中反复调用内置的过滤器相关API,下图红框中的都可以:
  运行服务,用Postman验证效果,如下图红框,Gateway在响应body中成功添加了一个key&value:
  代码配置路由和yml配置是否可以混搭?前面有两个问题,接下来回答第二个,咱们在application.yml中增加一个路由配置: server:   #服务端口   port: 8081 spring:   application:     name: gateway-change-body   cloud:     gateway:       routes:         - id: path_route_str           uri: http://127.0.0.1:8082           predicates:             - Path=/hello/str把 gateway-change-body 服务启动起来,此时已经有了两个路由配置,一个在代码中,一个在yml中,先试试yml中的这个,如下图没问题:
  再试试代码配置的路由,如下图,结论是 代码配置路由和yml配置 可以 混搭
  如何处理异常还有个问题必须要面对:修改请求或者响应body的过程中,如果发现问题需要提前返回错误(例如必要的字段不存在),代码该怎么写? 咱们修改请求body的代码集中在RequestBodyRewrite.java,增加下图红框内容:
  再来试试,这次请求参数中不包含 user-id ,收到Gateway返回的错误信息如下图:
  看看控制台,能看到代码中抛出的异常信息:
  此时,聪明的您应该发现问题所在了:咱们想告诉客户端具体的错误,但实际上客户端收到的是被Gateway框架处理后的内容 篇幅所限,上述问题从分析到解决的过程,就留给下一篇文章吧 本篇的最后,请容许欣宸唠叨两句,聊聊为何要网关来修改请求和响应body的内容,如果您没兴趣还请忽略 网关(Gateway)为什么要做这些?看过开篇的两个图,聪明的您一定发现了问题:为什么要破坏原始数据,一旦系统出了问题如何定位是服务提供方还是网关?按照欣宸之前的经验,尽管网关会破坏原始数据,但只做一些简单固定的处理,一般以添加数据为主,网关不了解业务,最常见的就是鉴权、添加身份或标签等操作前面的图中确实感受不到网关的作用,但如果网关后面有多个服务提供者,如下图,这时候诸如鉴权、获取账号信息等操作由网关统一完成,比每个后台分别实现一次更有效率,后台可以更加专注于自身业务:
  经验丰富的您可能会对我的狡辩不屑一顾:网关统一鉴权、获取身份,一般会把身份信息放入请求的header中,也不会修改请求和响应的内容啊,欣宸前面的一堆解释还是没说清楚为啥要在网关位置修改请求和响应的内容!好吧,面对聪明的您,我摊牌了:本篇只是从技术上演示Spring Cloud Gateway如何修改请求和响应内容,请不要将此技术与实际后台业务耦合;欢迎关注头条号:程序员欣宸学习路上,你不孤单,欣宸原创一路相伴...

若俄罗斯最终战败,中国必须做最坏的打算,要为普京做三件事情!俄罗斯若彻底战败,中国必须做哪些最坏的打算,这三件要为普京做的事又为何是重中之重?俄乌军事冲突或已进入分水岭,刚刚撮合沙特伊朗和谈的中国,紧接着于21日在莫斯科与俄罗斯进行了两国元金博洋携七国军队第六度征战世锦赛磨合阶段放手一搏北京时间3月23日晚,花样滑冰世锦赛男子单人滑短节目的比赛在日本埼玉上演。金博洋以第19名的成绩顺利晋级男单自由滑。第六次登上世锦赛赛场的金博洋,带着他仅在四大洲锦标赛亮相过的新赛揭露美国为俄罗斯准备了50年的阴谋看清美国反俄派如何分裂俄罗斯头条创作挑战赛通过俄乌冲突,继而看清美国分裂苏联,分裂俄罗斯的阴谋其实一直都在持续,美国人是如何一步步做到这些的。通过这次拜登访问乌克兰,也可以证明拜登也是这个行动的执行者之一,追北约考虑在俄边境部署30万军队3月6日,立陶宛约纳瓦,德国防长皮斯托留斯访问北约增强前沿存在的特遣队期间向德军官兵发表讲话。视觉中国供图2022年2月6日,德国,2000名美军抵达欧洲应对俄乌危机。自去年以来,在博鳌乘风破浪的俄罗斯创业者3月22日,亚历山大在海南博鳌玩风翼冲浪。新华社记者张丽芸摄俄罗斯人亚历山大住在海南省琼海市博鳌镇,是一位冲浪品牌创业者。2011年,他来到海南旅游,被海南的气候和生活吸引,于是他山西省成功开行今年第9列去往俄罗斯的中欧班列3月24日,伴随声声汽笛,一列装载近800吨涤纶无纺布食品添加剂陶瓷餐具柴油发电机等货物的中欧班列从中鼎物流园站缓缓驶出,开往俄罗斯。这是我省成功开行的第663列中欧班列,也是今年外国在港领团和商界参访大湾区收获颇丰冀建立投资合作关系中新社香港3月24日电(记者魏华都)感知大湾区,开拓新机遇外国在港领团和商界参访粤港澳大湾区活动日前结束。团员们赞扬大湾区企业取得的成就,并希望建立合作关系和投资大湾区。图为外宾在比特币BTC衍生品需求飙升,但其含义是什么?小探本期为大家带来的内容主题是衍生品需求飙升,但其含义是什么?欢迎大家关注小探,小探每天都会给您献上关于币圈的优质内容哦衍生品市场的比特币需求利用了银行倒闭引发的资金流入。抛售压力全球最大硅钢供应商宝钢重磅产线投产完全面向新能源汽车行业新能源汽车快速发展的背景下,其驱动电机用无取向硅钢产品因工序流程长工艺窗口窄生产难度大,全球具备大批量稳定生产顶级高牌号产品能力的企业较少,供应一直处于紧平衡。澎湃新闻记者从中国上大V空降植信投资研究院秘书长邓志超对谈Vlubhouse粉丝跟资深大V面对面聊天拥有被现场高效答疑解惑的沉浸感,是加入Vlubhouse就可以轻松获得的粉丝体验。我们会不定期邀请到已入驻一财号的大V空降Vlubhouse一财号粉丝群,并提前0。6折成交首单消金不良包买贵了吗?近日,首单消费金融个人消费信用不良贷款成功转让。据市场消息,富安资产以114。5万元的价格拿下了首个消金不良资产包,拉开了持牌消金行业个贷不良批转的序幕。根据中邮消金发布的关于第1
詹姆斯韦伯望远镜将目光投向115亿年前捕捉到令人惊叹的ampampquot彩虹结ampampquot詹姆斯韦伯在宇宙中发现了又一个壮观的景象。这一次,太空望远镜发现了一个彩虹结,由一个极度红色的类星体以及它周围的几个巨大的星系组成。这个结应该存在于115亿年前。来自詹姆斯韦伯的最爬泰山超实用攻略来喽给大家分享一下泰山攻略啦我们是8月23日晚上大概九点左右到达的泰山,我们定了一个性价比超高的酒店,尚维酒店!!距离泰安站特别近,酒店环境真的好,卫生也超级好,房间里配有中央空调,化NJPW摔角王国新Logo神似摔角狂热36?WWE或与GCW展开合作前些日子WWE传出了即将取消Day1迎新赛的消息,于是整个摔角界的开年大战似乎又变成了新日摔的摔角王国(WrestleKingdom)。时至今日,这项赛事已举办过16届,而新日摔也金属装甲全新升级,影驰GeForceRTX4090金属大师提及高性能高颜值显卡,那影驰旗下的游戏显卡是绕不开的话题。影驰的显卡在消费者的口碑非常不错,凭借着全金属外壳优秀的做工扎实的用料和无光设计,给玩家留下了深刻的印象,非常适合搭建有质解放双手的吹风机,首创立式设计,速干养发也可以这样简单近几年科技互联网得到了飞速的发展,助推传统企业科技赋能,提升产品的核心竞争力。也为新兴产品和新兴品牌提供了入场机会。产品的升级,品牌的踊跃入场,让各类产品能够迅速普及到千家万户,让羊了个羊就是个广告播种机最近羊了个羊火遍全网,此游戏的第一关只要你手不残疾都能通关,而到了第二关完全不能通关,下图是我刚玩的一把场上就剩下这几样东西,怎么拼都不可能拼到一块。这款游戏说白了就是广告播种机,彩电双11未至胜负已定?踩对大趋势的品牌早就赢得先手Titer撰稿今年双11,用行业套话讲,又是一次史无前例的激烈,彩电市场更是毫无悬念。不过,在倒计时尚有半个月时,我们似乎已对胜负,或者说头魁获得者的身份,有了较为清晰的判断。最近免费无广告无水印!这几款扫描APP,让你的办公更高效因为疫情的原因,现在不少城市动不动就静默,这严重影响了大家的工作与学习,而居家办公与上网课也让打印文件扫描等成了必不可少的需求,大部分家庭并没有打印机,虽然打印的问题只能通过打印机世界乒联WTT澳门站王楚钦孙颖莎夺冠后自拍合影花絮工作人员你们自拍一张吧大头来吧,我们四个人一起拍一张。小胖不了,不了,还是你俩拍吧桐桐对,对,就你俩拍大头你不和我们拍?别闹别闹(内心你俩可太看事了)害羞莎莎内心我该说话吗我该看哪地球上的人类,可能会被消灭?盘点5个来自太空的致命事件2022年8月科学进展杂志上出现了一篇研究恐龙灭绝方式的论文,由美国亚利桑那大学得克萨斯大学等学者组成的团队,在西非海岸的海底发现了一个巨大的陨石坑,而该陨石坑和撞击地球造成恐龙灭秋不补,冬吃苦,建议男人有条件常吃5样,精气足健康过冬秋不补,冬吃苦,建议男人有条件常吃这5样,身体更健康,为入冬打基础进入10月下旬,秋天已经来到尾声,冬天要来了。因此要抓住秋天的尾巴,好好地调理自己的身体,健康的过冬天。对于一个家