摘要:歡迎訪問我的歡迎訪問我的內容所有原創文章分類匯總及配套源碼,涉及等本篇概覽本篇概覽作為實戰系列的第九篇,咱們聊聊如何用修改原始請求和響應內容,以及修改過程中遇到的問題首先是修改請求,如下圖,瀏覽器是請求發起方,真實參數只有,經過網關時被塞
https://github.com/zq2599/blog_demos
內容:所有原創文章分類匯總及配套源碼,涉及Java、Docker、Kubernetes、DevOPS等;
作為《Spring Cloud Gateway實戰》系列的第九篇,咱們聊聊如何用Spring Cloud Gateway修改原始請求和響應內容,以及修改過程中遇到的問題
首先是修改請求body,如下圖,瀏覽器是請求發起方,真實參數只有user-id,經過網關時被塞入字段user-name,于是,后臺服務收到的請求就帶有user-name字段了
名稱 | 鏈接 | 備注 |
---|---|---|
項目主頁 | https://github.com/zq2599/blog_demos | 該項目在GitHub上的主頁 |
git倉庫地址(https) | https://github.com/zq2599/blog_demos.git | 該項目源碼的倉庫地址,https協議 |
git倉庫地址(ssh) | git@github.com:zq2599/blog_demos.git | 該項目源碼的倉庫地址,ssh協議 |
@PostMapping("/change") public Map change(@RequestBody Map map) { map.put("response-tag", dateStr()); return map; }
可見新增的web接口很簡單:將收到的請求數據作為返回值,在里面添加了一個鍵值對,然后返回給請求方,有了這個接口,咱們就能通過觀察返回值來判斷Gateway對請求和響應的操作是否生效
來試一下,先啟動nacos(provider-hello需要的)
再運行provider-hello應用,用Postman向其發請求試試,如下圖,符合預期:
@Beanpublic 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();}
@Beanpublic 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();}
廢話不說,在父工程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;@SpringBootApplicationpublic class ChangeBodyApplication { public static void main(String[] args) { SpringApplication.run(ChangeBodyApplication.class,args); }}
server: #服務端口 port: 8081spring: application: name: gateway-change-body
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;@Slf4jpublic 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)); } }}
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;@Configurationpublic 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(); }}
接下來開發修改響應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;@Slf4jpublic 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)); } }}
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;@Configurationpublic 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(); }}
server: #服務端口 port: 8081spring: application: name: gateway-change-body cloud: gateway: routes: - id: path_route_str uri: http://127.0.0.1:8082 predicates: - Path=/hello/str
還有個問題必須要面對:修改請求或者響應body的過程中,如果發現問題需要提前返回錯誤(例如必要的字段不存在),代碼該怎么寫?
咱們修改請求body的代碼集中在RequestBodyRewrite.java,增加下圖紅框內容:
此時,聰明的您應該發現問題所在了:咱們想告訴客戶端具體的錯誤,但實際上客戶端收到的是被Gateway框架處理后的內容
篇幅所限,上述問題從分析到解決的過程,就留給下一篇文章吧
本篇的最后,請容許欣宸嘮叨兩句,聊聊為何要網關來修改請求和響應body的內容,如果您沒興趣還請忽略
看過開篇的兩個圖,聰明的您一定發現了問題:為什么要破壞原始數據,一旦系統出了問題如何定位是服務提供方還是網關?
按照欣宸之前的經驗,盡管網關會破壞原始數據,但只做一些簡單固定的處理,一般以添加數據為主,網關不了解業務,最常見的就是鑒權、添加身份或標簽等操作
前面的圖中確實感受不到網關的作用,但如果網關后面有多個服務提供者,如下圖,這時候諸如鑒權、獲取賬號信息等操作由網關統一完成,比每個后臺分別實現一次更有效率,后臺可以更加專注于自身業務:
經驗豐富的您可能會對我的狡辯不屑一顧:網關統一鑒權、獲取身份,一般會把身份信息放入請求的header中,也不會修改請求和響應的內容啊,欣宸前面的一堆解釋還是沒說清楚為啥要在網關位置修改請求和響應的內容!
好吧,面對聰明的您,我攤牌了:本篇只是從技術上演示Spring Cloud Gateway如何修改請求和響應內容,請不要將此技術與實際后臺業務耦合;
微信搜索「程序員欣宸」,我是欣宸,期待與您一同暢游Java世界...
https://github.com/zq2599/blog_demos
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/124815.html
摘要:歡迎訪問我的歡迎訪問我的內容所有原創文章分類匯總及配套源碼,涉及等本篇概覽本篇概覽作為實戰系列的第五篇,是時候了解過濾器的作用了,本篇咱們一起來了解內置好的過濾器,真是種類繁多功能強大過濾器顧名思義,就是在請求頭部添加指定的內容帶有的完整配歡迎訪問我的GitHubhttps://github.com/zq2599/blog_demos內容:所有原創文章分類匯總及配套源碼,涉及Java、Doc...
摘要:單服務我們簡單編寫一個請求地址,輸出字符串信息,添加依賴如下所示配置文件如下所示服務名注冊到服務端口號配置該服務的服務名稱為,這里對應的。 在上一篇文章Spring Cloud GateWay 路由轉發規則介紹中我們講解了SpringCloud Gateway內部提供的斷言、謂語,讓我們可以組合更精確的業務場景進行請求,既然SpringCloud GateWay擔任了網關的角色,在之前...
摘要:組合示例相同的也可以配置多個,請求的轉發是必須滿足所有的后才可以進行路由轉發,組合使用示例如下所示總結本章節講解了的相關謂詞斷言基本使用方式,內部提供了很多種靈活的路由轉發規則,在同一個路由內存在多個時,同時滿足規則后請求才會被路由轉發。 Spring在因Netflix開源流產事件后,在不斷的更換Netflix相關的組件,比如:Eureka、Zuul、Feign、Ribbon等,Zuu...
摘要:歡迎訪問我的歡迎訪問我的內容所有原創文章分類匯總及配套源碼,涉及等本篇概覽本篇概覽本文是實戰系列的第八篇,經過前面的學習,咱們對過濾器已了解得差不多,今天來補全過濾器的最后一個版塊限流默認的限流器是基于實現的,限流算法是大家熟悉的令牌桶關于歡迎訪問我的GitHubhttps://github.com/zq2599/blog_demos內容:所有原創文章分類匯總及配套源碼,涉及Java、Doc...
閱讀 3406·2021-11-24 09:39
閱讀 1797·2021-11-17 09:33
閱讀 3503·2021-10-12 10:12
閱讀 5019·2021-09-22 15:51
閱讀 1111·2019-08-30 13:11
閱讀 3571·2019-08-30 10:59
閱讀 564·2019-08-30 10:48
閱讀 1311·2019-08-26 13:48