您好,登錄后才能下訂單哦!
本篇內(nèi)容介紹了“如何理解Spring Cloud網(wǎng)關(guān)服務(wù)zuul ”的有關(guān)知識,在實(shí)際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!
可以看到服務(wù)端口和注冊中心都在配置文件中配置化
上一篇我們講了如何搭建網(wǎng)關(guān)zuul 服務(wù)。實(shí)現(xiàn)了基本的轉(zhuǎn)發(fā)功能。這篇文章我們要講述zuul過濾器的使用。和三個參數(shù)的使用
ribbon-isolation-strategy
信號量模式 在該模式下,接收請求和執(zhí)行下游依賴在同一個線程內(nèi)完成,不存在線程上下文切換所帶來的性能開銷。默認(rèn)信號量模式
線程池 在該模式下,用戶請求會被提交到各自的線程池中執(zhí)行,把執(zhí)行每個下游服務(wù)的線程分離,從而達(dá)到資源隔離的作用。當(dāng)線程池來不及處理并且請求隊(duì)列塞滿時(shí),新進(jìn)來的請求將快速失敗,可以避免依賴問題擴(kuò)散。
隔離機(jī)制 Spring Cloud 默認(rèn)的隔離機(jī)制hystrix 去做限流、熔斷、隔離。一個是基于信號量。一個是基于線程池去完成
ignored-services
忽略指定的服務(wù)
ignored—patterns
忽略指定的url 路徑
ignored-headers
忽略指定的header 頭部信息
sensitiveHeaders
字段比較敏感,不希望傳遞給下游微服務(wù)。 設(shè)置空沒有要忽略的敏感字段。全部傳給下游服務(wù)
在上面ignored-headers 和 sensitiveHeaders 職責(zé)是有重疊的部分。其實(shí)他們是有著關(guān)系存在的。sensitiveHeaders的內(nèi)容會最終合并到ignored-headers內(nèi)。
驗(yàn)證一下 sensitiveHeaders 字段設(shè)置全區(qū)忽略 X-ABC
消費(fèi)者服務(wù) sensitiveHeaders 指定忽略 X-ABC,Authorization
服務(wù)提供者轉(zhuǎn)發(fā)不做任何調(diào)整 在服務(wù)提供者 和 服務(wù)消費(fèi)者 服務(wù)上。都創(chuàng)建一個 UrlFilter 攔截器 先設(shè)置一下 zuul的yml文件
zuul: host: # 目標(biāo)主機(jī)的最大連接數(shù),默認(rèn)值為200 max-total-connections: 500 # 每個主機(jī)的初始連接數(shù),默認(rèn)值為20 max-per-route-connections: 100 routes: discovery-server: path: /server/** serviceId: cloud-discovery-server client-common: path: /client/** serviceId: cloud-discovery-client sensitiveHeaders: X-ABC,X-Foo # 所有路由的默認(rèn)Hystrix隔離模式(ExecutionIsolationStrategy)為SEMAPHORE。如果此隔離模式是首選,則zuul.ribbonIsolationStrategy可以更改為THREAD ribbon-isolation-strategy: thread # 這個屬性意思,* 忽略未指定的服務(wù)列表 有具體服務(wù)名稱 忽略指定的服務(wù) ignored-services: "*" # 忽略指定的url 路徑 ignored—patterns: # 忽略指定的header 頭部信息 ignored-headers: Authorization # 字段比較敏感,不希望傳遞給下游微服務(wù)。 設(shè)置空沒有要忽略的敏感字段。全部傳給下游服務(wù) sensitive-headers: X-ABC ribbon: eager-load: # 強(qiáng)制加載,不設(shè)置會進(jìn)行懶加載。spring 第一次請求會非常慢 enabled: true
package com.xian.cloud.filter; import lombok.extern.slf4j.Slf4j; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.util.Enumeration; /** * <Description> * * @author xianliru@100tal.com * @version 1.0 * @createDate 2019/10/29 13:57 */ @WebFilter(filterName = "test",urlPatterns = "/*") @Slf4j public class UrlFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { log.warn("UrlFilter init......."); } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { Enumeration<String> attributeNames = servletRequest.getAttributeNames(); HttpServletRequest req = (HttpServletRequest) servletRequest; String requestURI = req.getRequestURI(); String header = req.getHeader("X-Foo"); String abc = req.getHeader("X-ABC"); String authorization = req.getHeader("Authorization"); String tom = req.getParameter("tom"); String mike = req.getParameter("mike"); log.warn("過濾器:請求地址"+requestURI); log.warn("uuid:{}",header); log.warn("abc uuid:{}",abc); log.warn("authorization :{}",authorization); log.warn("tom :{}",tom); log.warn("mike :{}",mike); filterChain.doFilter(servletRequest, servletResponse); } @Override public void destroy() { log.warn(" 過濾器被銷毀"); } }
啟動類上添加 @ServletComponentScan 用于掃描 過濾器 @WebFilter注解
package com.xian.cloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.web.servlet.ServletComponentScan; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; /** * @Author: xlr * @Date: Created in 2:44 PM 2019/10/27 */ @EnableDiscoveryClient @SpringBootApplication //新增注解 @ServletComponentScan public class DiscoveryServerApplication { public static void main(String[] args) { SpringApplication.run(DiscoveryServerApplication.class, args); } }
使用postman 請求服務(wù) 服務(wù)端打印日志
2019-10-30 11:10:35.822 WARN 48882 --- [nio-9012-exec-8] com.xian.cloud.filter.UrlFilter : 過濾器:請求地址/server/hello 2019-10-30 11:10:35.826 WARN 48882 --- [nio-9012-exec-8] com.xian.cloud.filter.UrlFilter : uuid:x-foo 2019-10-30 11:10:35.826 WARN 48882 --- [nio-9012-exec-8] com.xian.cloud.filter.UrlFilter : abc uuid:null 2019-10-30 11:10:35.827 WARN 48882 --- [nio-9012-exec-8] com.xian.cloud.filter.UrlFilter : authorization :null 2019-10-30 11:10:35.827 WARN 48882 --- [nio-9012-exec-8] com.xian.cloud.filter.UrlFilter : tom :null 2019-10-30 11:10:35.828 WARN 48882 --- [nio-9012-exec-8] com.xian.cloud.filter.UrlFilter : mike :null 2019-10-30 11:10:35.852 INFO 48882 --- [nio-9012-exec-8] c.x.cloud.controller.DiscoverCotroller : invoked name = xian age = 20
sensitive-headers、ignored-headers (abc、authorization都在zuul被過濾掉)全局設(shè)置生效。
我們再次請求client 服務(wù)接口
在看一下 客戶端打印日志
2019-10-30 11:17:05.813 WARN 50223 --- [nio-9011-exec-3] com.xian.cloud.filter.UrlFilter : 過濾器:請求地址/client/test 2019-10-30 11:17:05.813 WARN 50223 --- [nio-9011-exec-3] com.xian.cloud.filter.UrlFilter : uuid:null 2019-10-30 11:17:05.813 WARN 50223 --- [nio-9011-exec-3] com.xian.cloud.filter.UrlFilter : abc uuid:null 2019-10-30 11:17:05.813 WARN 50223 --- [nio-9011-exec-3] com.xian.cloud.filter.UrlFilter : authorization :null 2019-10-30 11:17:05.813 WARN 50223 --- [nio-9011-exec-3] com.xian.cloud.filter.UrlFilter : tom :null 2019-10-30 11:17:05.813 WARN 50223 --- [nio-9011-exec-3] com.xian.cloud.filter.UrlFilter : mike :null
全局設(shè)置,和單個服務(wù)定制設(shè)置 全部生效。
spring cloud Zuul包含了對請求的路由和過濾2個功能。路由功能負(fù)責(zé)將請求轉(zhuǎn)發(fā)到具體的微服務(wù)上,而過濾器負(fù)責(zé)對請求的處理過程進(jìn)行干預(yù),是實(shí)現(xiàn)權(quán)限校驗(yàn)、服務(wù)聚合等功能的基礎(chǔ)。
在實(shí)際運(yùn)行時(shí),路由映射和請求轉(zhuǎn)發(fā)是由幾個不同的過濾器完成的。每一個進(jìn)入zuul的http請求都會經(jīng)過一系列的過濾器處理鏈得到請求響應(yīng)并返回給客戶端。
zuul1.0 對流量的路由分發(fā)和過濾倆個功能。路由讓流量分發(fā)到內(nèi)部的微服務(wù)集群上。過濾對請求進(jìn)行修改或者做個性化處理。實(shí)現(xiàn)鑒權(quán)、安全、監(jiān)控、日志等。
運(yùn)行過程中,流量請求會經(jīng)過一系列的過濾器最終轉(zhuǎn)發(fā)到對應(yīng)的服務(wù)上去。
zuul 路由器主要根絕FilterType類型分為四種類型。一個靜態(tài)響應(yīng)StaticResponseFilter
pre 在請求被路由之前調(diào)用。對應(yīng)spring boot 工程Filer 中的 doFilter 方法。
route 用于路由到原點(diǎn),使用http 協(xié)議調(diào)用。可以理解負(fù)責(zé)轉(zhuǎn)發(fā)請求到微服務(wù)
error 錯誤處理,在處理請求發(fā)生錯誤時(shí)被調(diào)用
post 用于后路由過濾,在route和error過濾器之后被調(diào)用
FilterTypeEnum 枚舉類
package com.xian.cloud.enums; import lombok.Getter; /** * <Description> * * @author xianliru@100tal.com * @version 1.0 * @createDate 2019/10/29 13:01 */ @Getter public enum FilterTypeEnum { PRE("pre","前置過濾"), ROUTE("route","路由請求時(shí)被調(diào)用"), POST("post","后置過濾器"), ERROR("error","后置錯誤處理"); private String type; private String desc; FilterTypeEnum(String type,String desc){ this.type = type; this.desc = desc; } }
過濾器代碼編寫
package com.xian.cloud.filter; import com.netflix.zuul.ZuulFilter; import com.netflix.zuul.context.RequestContext; import com.netflix.zuul.exception.ZuulException; import com.xian.cloud.enums.FilterTypeEnum; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.ArrayList; import java.util.List; import java.util.UUID; /** * <Description> * * @author xianliru@100tal.com * @version 1.0 * @createDate 2019/10/29 12:57 */ @Component @Slf4j public class BannedAccessFilter extends ZuulFilter { /** * 路由器的類型指定 * @return */ @Override public String filterType() { return FilterTypeEnum.PRE.getType(); } /** * 執(zhí)行順序 數(shù)值越小。執(zhí)行順序越靠前 * @return */ @Override public int filterOrder() { return 0; } /** * 返回一個boolean值來判斷該過濾器是否要執(zhí)行。我們可以通過此方法來指定過濾器的有效范圍。 * @return */ @Override public boolean shouldFilter() { RequestContext context = RequestContext.getCurrentContext(); HttpServletRequest request = context.getRequest(); String requestURI = request.getRequestURI(); if(StringUtils.isNotBlank(requestURI) && (requestURI.contains("client") || requestURI.contains("server"))){ return true; } return false; } /** * 核心業(yè)務(wù)處理 * @return * @throws ZuulException */ @Override public Object run() throws ZuulException { RequestContext context = RequestContext.getCurrentContext(); HttpServletResponse servletResponse = context.getResponse(); String uuid = UUID.randomUUID().toString(); //重寫 X-Foo X-ABC值 context.addZuulRequestHeader("X-Foo", uuid); context.addZuulRequestHeader("X-ABC",uuid); log.info("X-Foo:{}",uuid); return null; } }
run方法是核心業(yè)務(wù)處理的方法 postman 請求 http://127.0.0.1:9083/server/server/hello?name=1111 攜帶之前設(shè)置的header參數(shù)
服務(wù)器打印日志
2019-10-30 14:44:44.841 WARN 48882 --- [nio-9012-exec-9] com.xian.cloud.filter.UrlFilter : 過濾器:請求地址/server/hello 2019-10-30 14:44:44.842 WARN 48882 --- [nio-9012-exec-9] com.xian.cloud.filter.UrlFilter : uuid:a65b2244-e9a5-456d-968f-eaaba45b6f49 2019-10-30 14:44:44.842 WARN 48882 --- [nio-9012-exec-9] com.xian.cloud.filter.UrlFilter : abc uuid:null 2019-10-30 14:44:44.842 WARN 48882 --- [nio-9012-exec-9] com.xian.cloud.filter.UrlFilter : authorization :null 2019-10-30 14:44:44.842 WARN 48882 --- [nio-9012-exec-9] com.xian.cloud.filter.UrlFilter : tom :null 2019-10-30 14:44:44.842 WARN 48882 --- [nio-9012-exec-9] com.xian.cloud.filter.UrlFilter : mike :null 2019-10-30 14:44:44.844 INFO 48882 --- [nio-9012-exec-9] c.x.cloud.controller.DiscoverCotroller : invoked name = 1111 age = 20
可以看到 postman設(shè)置的X-Foo 值被 BannedAccessFilter run方法業(yè)務(wù)覆蓋掉了
攔截的請求對參數(shù)的修改操作都是在這里。這里單獨(dú)介紹一下 RequestContext 這個類
官方文檔描述
To pass information between filters, Zuul uses a RequestContext. Its data is held in a ThreadLocal specific to each request. Information about where to route requests, errors and the actual HttpServletRequest and HttpServletResponse are stored there. The RequestContext extends ConcurrentHashMap, so anything can be stored in the context. FilterConstants contains the keys that are used by the filters installed by Spring Cloud Netflix (more on these later).
請求要在過濾器之間傳遞信息,Zuul使用 RequestContext。其數(shù)據(jù)按照每個請求的ThreadLocal進(jìn)行。關(guān)于路由請求,錯誤以及實(shí)際HttpServletRequest和HttpServletResponse的路由信息。RequestContext擴(kuò)展ConcurrentHashMap,所以任何東西都可以存儲在上下文中。
ThreadLocal保證了請求與請求都是獨(dú)立的,相互不影響。擴(kuò)展ConcurrentHashMap 保證內(nèi)部過濾器并發(fā)操作的安全性。
需要注意點(diǎn) 都在代碼注釋上描述出來了。請根據(jù)自己的業(yè)務(wù)場景定制自己的過濾器。
package com.xian.cloud.filter; import com.alibaba.fastjson.JSONObject; import com.netflix.zuul.ZuulFilter; import com.netflix.zuul.context.RequestContext; import com.netflix.zuul.exception.ZuulException; import com.netflix.zuul.http.HttpServletRequestWrapper; import com.netflix.zuul.http.ServletInputStreamWrapper; import com.xian.cloud.enums.FilterTypeEnum; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Component; import org.springframework.util.StreamUtils; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.io.InputStream; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * <Description> * * @author xianliru@100tal.com * @version 1.0 * @createDate 2019/10/29 16:07 */ @Component @Slf4j public class UpdateParamsFilter extends ZuulFilter { @Override public String filterType() { return FilterTypeEnum.PRE.getType(); } @Override public int filterOrder() { return 1; } @Override public boolean shouldFilter() { return true; } @Override public Object run() throws ZuulException { // 獲取到request RequestContext ctx = RequestContext.getCurrentContext(); HttpServletRequest request = ctx.getRequest(); // 獲取請求參數(shù)name String name = ""; try { // 請求方法 String method = request.getMethod(); log.info(String.format("%s >>> %s", method, request.getRequestURL().toString())); // 獲取請求的輸入流 InputStream in = request.getInputStream(); String body = StreamUtils.copyToString(in, Charset.forName("UTF-8")); // 如果body為空初始化為空json if (StringUtils.isBlank(body)) { body = "{}"; } log.info("body" + body); // 轉(zhuǎn)化成json JSONObject json = JSONObject.parseObject(body); // 關(guān)鍵步驟,一定要get一下,下面才能取到值requestQueryParams if ("GET".equals(method)) { request.getParameterMap(); Map<String, List<String>> requestQueryParams = ctx.getRequestQueryParams(); if (requestQueryParams == null) { requestQueryParams = new HashMap<>(); } //TODO 寫業(yè)務(wù)代碼 List<String> arrayList = new ArrayList<>(); arrayList.add("hello mike"); //requestQueryParams.put("mike",arrayList); ctx.setRequestQueryParams(requestQueryParams); } //post和put需重寫HttpServletRequestWrapper if ("POST".equals(method) || "PUT".equals(method)) { //TODO 在這里修改或者添加內(nèi)容 json.put("tom","hello tom"); String newBody = json.toString(); final byte[] reqBodyBytes = newBody.getBytes(); // 重寫上下文的HttpServletRequestWrapper ctx.setRequest(new HttpServletRequestWrapper(request) { @Override public ServletInputStream getInputStream() throws IOException { return new ServletInputStreamWrapper(reqBodyBytes); } @Override public int getContentLength() { return reqBodyBytes.length; } @Override public long getContentLengthLong() { return reqBodyBytes.length; } }); } } catch (IOException e) { e.printStackTrace(); } return null; } }
“如何理解Spring Cloud網(wǎng)關(guān)服務(wù)zuul ”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。