Spring Cloud Zuul:統一網關
Spring Cloud Zuul 提供動態路由,監控,彈性,安全等邊緣服務,將細粒度的服務組合起來提供一個粗粒度的服務,所有請求都導入一個統一的入口,那麼整個系統只需要暴露一個服務,對外屏蔽服務端實現細節,這樣也減少了客戶端與服務器的網絡調用次數,這就是api gateway,也是Zuul可以幫我們實現的功能。
開發環境 | 版本 |
---|---|
IDEA | 2018.2.6 |
JDK | 1.8 |
Spring Boot | 2.0.6 |
Spring Cloud | Finchley.SR2 |
路由
新建項目zuul
Maven依賴:
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<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>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
配置文件(可以參照前幾章內容將配置放到git倉庫):
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/,http://localhost:8762/eureka/
instance:
prefer-ip-address: true
instance-id: ${spring.cloud.client.ip-address}:${server.port}
# hostname: ZuulName
spring:
application:
name: zuul
cloud:
config:
discovery:
enabled: true
service-id: config
profile: dev
啓動類添加@EnableZuulProxy註解:
@SpringBootApplication
@EnableZuulProxy
public class ZuulApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulApplication.class, args);
}
}
在前面幾章的項目均已啓動的前提下,將zuul項目VM options設置-DServer.port=8061,運行成功後訪問http://localhost:8061/provider/hello/chung,發現zuul會自動將請求路由至provider服務。
此路徑中得到provider爲serviceId
自定義路由
進行如下配置,運行成功後訪問http://localhost:8061/myRoute/hello/chung,zuul也會自動將請求路由至provider服務。
zuul:
routes:
provider: /myRoute/**
PRE_TYPE Zuul Filter
前置過濾器可以實現限流、鑑權、參數校驗等功能。
鑑權、參數校驗
@Component
public class PreFilter extends ZuulFilter {
@Override
public String filterType() {
return PRE_TYPE;
}
@Override
public int filterOrder() {
return PRE_DECORATION_FILTER_ORDER - 1;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() {
RequestContext currentContext = RequestContext.getCurrentContext();
HttpServletRequest request = currentContext.getRequest();
// 鑑權
if ("/provider/hello/send".equals(request.getRequestURI())) {
if (false) {
currentContext.setSendZuulResponse(false);
currentContext.setResponseStatusCode(HttpStatus.SC_UNAUTHORIZED);
}
}
// 參數校驗
if (StringUtils.isEmpty(request.getParameter("token"))) {
currentContext.setSendZuulResponse(false);
currentContext.setResponseStatusCode(HttpStatus.SC_UNAUTHORIZED);
}
return null;
}
}
API限流
使用令牌桶算法,Google的RateLimiter工具。
@Component
public class RateLimitFilter extends ZuulFilter {
private static final RateLimiter RATE_LIMITER = RateLimiter.create(100);
@Override
public String filterType() {
return PRE_TYPE;
}
@Override
public int filterOrder() {
return SERVLET_DETECTION_FILTER_ORDER - 1;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() {
if (!RATE_LIMITER.tryAcquire()) {
RequestContext currentContext = RequestContext.getCurrentContext();
currentContext.setSendZuulResponse(false);
currentContext.setResponseStatusCode(HttpStatus.SC_SERVICE_UNAVAILABLE);
}
return null;
}
}
POST_TYPE Zuul Filter
後置過濾器可以實現統計、日誌記錄等功能。
@Component
public class PostFilter extends ZuulFilter {
@Override
public String filterType() {
return POST_TYPE;
}
@Override
public int filterOrder() {
return SEND_RESPONSE_FILTER_ORDER - 1;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() {
RequestContext currentContext = RequestContext.getCurrentContext();
HttpServletResponse response = currentContext.getResponse();
/**Some Code**/
response.setHeader("POST_HEADER", UUID.randomUUID().toString());
return null;
}
}