Zuul--學習筆記(5)
目錄
一、參考Spring Cloud官方文檔
--1、路由器和過濾器:Zuul
--2、如何加入Zuul
--3、嵌入式Zuul反向代理
--4、@EnableZuulProxy與@EnableZuulServer
二、實操
--1、注冊中心、網關路由器、用戶服務提供者、訂單服務提供者
--2、zuul-demo的配置
--3、user-server配置
--4、order-server配置
--5、運行結果
----5.1、由euraka發現服務
----5.2、配置zuul的path
三、zuul過濾器
--1、Spring Cloud官方文檔
----1.1、如何編寫預過濾器
--2、實操
----2.1、在zuul-demo上修改
----2.2、運行結果
一、參考Spring Cloud官方文檔
1、路由器和過濾器:Zuul
路由在微服務體系結構的一個組成部分。例如,/
可以映射到您的Web應用程序,/api/users
映射到用戶服務,并將/api/shop
映射到商店服務。Zuul是Netflix的基于JVM的路由器和服務器端負載均衡器。
Netflix使用Zuul進行以下操作:
認證
洞察
壓力測試
金絲雀測試
動態路由
服務遷移
負載脫落
安全
靜態響應處理
主動/主動流量管理
Zuul的規則引擎允許基本上寫任何JVM語言編寫規則和過濾器,內置Java和Groovy。
2、如何加入Zuul
要在您的項目中包含Zuul,請使用組org.springframework.cloud
和artifact id spring-cloud-starter-zuul
的啟動器。
3、嵌入式Zuul反向代理
Spring Cloud已經創建了一個嵌入式Zuul代理,以簡化UI應用程序想要代理對一個或多個后端服務的呼叫的非常常見的用例的開發。此功能對于用戶界面對其所需的后端服務進行代理是有用的,避免了對所有后端獨立管理CORS和驗證問題的需求。
要啟用它,使用@EnableZuulProxy
注釋Spring Boot主類,并將本地調用轉發到相應的服務。按照慣例,具有ID“用戶”的服務將接收來自位于/users
(具有前綴stripped)的代理的請求。代理使用Ribbon來定位一個通過發現轉發的實例,并且所有請求都以 hystrix命令執行,所以故障將顯示在Hystrix指標中,一旦電路打開,代理將不會嘗試聯系服務。
要跳過自動添加的服務,請將zuul.ignored-services設置為服務標識模式列表。如果一個服務匹配一個被忽略的模式,而且包含在明確配置的路由映射中,那么它將被無符號。例:
application.yml
zuul:
ignoredServices: '*'
routes:
users: /myusers/**
在此示例中,除 “用戶” 之外,所有服務都被忽略。
要獲得對路由的更細粒度的控制,您可以獨立地指定路徑和serviceId:
application.yml
zuul:
routes:
users:
path: /myusers/**
serviceId: users_service
另一種方式是配合Ribbon來實現多個實例的路由訪問
application.yml
zuul:
routes:
users:
path: /myusers/**
serviceId: users
ribbon:
eureka:
enabled: false
users:
ribbon:
listOfServers: example.com,google.com
4、@EnableZuulProxy與@EnableZuulServer
Spring Cloud Netflix根據使用何種注釋來啟用Zuul安裝多個過濾器。@EnableZuulProxy是@EnableZuulServer的超集。換句話說,@EnableZuulProxy包含@EnableZuulServer安裝的所有過濾器。“代理”中的其他過濾器啟用路由功能。如果你想要一個“空白”Zuul,你應該使用@EnableZuulServer。
@EnableZuulProxy
/**
* Sets up a Zuul server endpoint and installs some reverse proxy filters in it, so it can
* forward requests to backend servers. The backends can be registered manually through
* configuration or via DiscoveryClient.
*
* @see EnableZuulServer for how to get a Zuul server without any proxying
*
* @author Spencer Gibb
* @author Dave Syer
* @author Biju Kunjummen
*/
@EnableCircuitBreaker
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(ZuulProxyMarkerConfiguration.class)
public @interface EnableZuulProxy {
}
@EnableZuulServer
/**
* Set up the application to act as a generic Zuul server without any built-in reverse
* proxy features. The routes into the Zuul server can be configured through
* {@link ZuulProperties} (by default there are none).
*
* @see EnableZuulProxy to see how to get reverse proxy out of the box
*
* @author Spencer Gibb
* @author Biju Kunjummen
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(ZuulServerMarkerConfiguration.class)
public @interface EnableZuulServer {
}
二、實操
1、注冊中心、網關路由器、用戶服務提供者、訂單服務提供者
- 注冊中心euraka-demo-server(參考Eureka--學習筆記(1))
- 網關路由器zuul-demo
- 用戶服務提供者user-server
- 訂單服務提供者order-server
2、zuul-demo的配置
pom.xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
啟動類
@SpringBootApplication
@EnableZuulProxy
public class ZuulDemoApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulDemoApplication.class, args);
}
}
application.yml
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka
server:
port: 8090
spring:
application:
name: api-gateway
3、user-server配置
pom.xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
application.yml
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
server:
port: 8091
spring:
application:
name: user-server
調用類
@RestController
@RequestMapping("/user")
public class UserController {
@GetMapping("/getmsg/{id}")
public String getmsg(@PathVariable Integer id){
return id + " baby are too young too simple";
}
}
4、order-server配置
pom.xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
application.yml
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
server:
port: 8092
spring:
application:
name: order-server
調用類
@RequestMapping("/order")
@RestController
public class OrderController {
@GetMapping("/count")
public String count(){
return "5";
}
}
5、運行結果
5.1、由euraka發現服務
UI監控界面
瀏覽器中輸入 http://localhosh:8090/order-server/order/count
瀏覽器中輸入 http://localhosh:8090/user-server/user/getmsg/2
5.2、配置zuul的path
zuul-demo中的application.yml
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka
server:
port: 8090
spring:
application:
name: api-gateway
zuul:
routes:
users:
path: /users/**
serviceId: user-server
orders:
path: /orders/**
serviceId: order-server
在瀏覽器中輸入http://localhost:8090/orders/order/count
在瀏覽器中輸入http://localhost:8090/users/user/getmsg/1
三、zuul過濾器
1、Spring Cloud官方文檔
1.1、如何編寫預過濾器
前置過濾器用于設置RequestContext中的數據,用于下游的過濾器。主要用例是設置路由過濾器所需的信息。
public class QueryParamPreFilter extends ZuulFilter {
@Override
public int filterOrder() {
return PRE_DECORATION_FILTER_ORDER - 1; // run before PreDecoration
}
@Override
public String filterType() {
return PRE_TYPE;
}
@Override
public boolean shouldFilter() {
RequestContext ctx = RequestContext.getCurrentContext();
return !ctx.containsKey(FORWARD_TO_KEY) // a filter has already forwarded
&& !ctx.containsKey(SERVICE_ID_KEY); // a filter has already determined serviceId
}
@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
if (request.getParameter("foo") != null) {
// put the serviceId in `RequestContext`
ctx.put(SERVICE_ID_KEY, request.getParameter("foo"));
}
return null;
}
}
上面的過濾器從foo請求參數填充SERVICE_ID_KEY。實際上,做這種直接映射并不是一個好主意,而是從foo的值來查看服務ID。
2、實操
2.1、在zuul-demo上修改
前置過濾器
@Component
public class ZuulPrefilter extends ZuulFilter {
@Override
public String filterType() {
return "pre";
}
@Override
public int filterOrder() {
return 0;
}
@Override
public boolean shouldFilter() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest req = ctx.getRequest();
String sign = req.getParameter("sign");
if(null == sign || "".equals(sign)){
return false;
}else if("abcd".equals(sign)){
return false;
}
return true;
}
@Override
public Object run() throws ZuulException {
RequestContext ctx = RequestContext.getCurrentContext();
ctx.setSendZuulResponse(false);
ctx.setResponseStatusCode(403);
return null;
}
}
2.2、運行結果
在瀏覽器輸入http://localhost:8090/orders/order/count?sign=1234
在瀏覽器輸入http://localhost:8090/orders/order/count?sign=abcd