1、什么是网关
在微服务架构中,通常会有多个服务提供者。设想一个电商系统,可能会有商品、订单、支付、用户等多个类型的服务,而每个类型的服务数量也会随着整个系统体量的增大也会随之增长和变更。前端在展示页面时可能需要从多个微服务中聚合数据,而且服务的划分位置结构可能会有所改变。网关就可以对外暴露聚合API,屏蔽内部微服务的微小变动,保持整个系统的稳定性。
2、什么是zuul
zuul是Spring Cloud全家桶中的微服务API网关。所有前端请求都会经过Zuul到达后端的Netflix应用程序。作为一个边界性质的应用程序,Zuul提供了动态路由、监控、弹性负载和安全功能。Zuul底层利用各种filter实现如下功能:
- 认证和安全 识别每个需要认证的资源,拒绝不符合要求的请求。
- 性能监测 在服务边界追踪并统计数据,提供精确的生产视图。
- 动态路由 根据需要将请求动态路由到后端集群。
- 压力测试 逐渐增加对集群的流量以了解其性能。
- 负载卸载 预先为每种类型的请求分配容量,当请求超过容量时自动丢弃。
- 静态资源处理 直接在边界返回某些响应。
3、建立一个网关服务
启动类添加@EnableZuulProxy
注解
@SpringBootApplication
@EnableZuulProxy
public class GatewayZuulApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayZuulDemoApplication.class, args);
}
}
配置文件示例:
spring:
application:
name: service-zuul
zuul:
routes:
api-a:
path: /api-a/**
serviceId: service-hi
# 以/api-a/ 开头的请求都转发给service-hi服务
api-b:
path: /api-b/**
serviceId: service-feign
# 以/api-b/ 开头的请求都转发给service-feign服务
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 60000 #设置API网关中路由转发请求的HystrixCommand执行超时时间
ribbon:
ConnectTimeout: 3000 #设置路由转发请求的时候,创建请求连接的超时时间
ReadTimeout: 60000 #用来设置路由转发请求的超时时间
4、zuul的自定义拦截器
继承com.netflix.zuul.ZuulFilter
,重写方法
@Component
public class MyFilter extends ZuulFilter {
private static Logger log = LoggerFactory.getLogger(MyFilter.class);
/**
* pre:路由之前
* routing:路由之时
* post: 路由之后
* error:发送错误调用
*
* @return 过滤器的类型
*/
@Override
public String filterType() {
return "pre";
}
/**
* 过滤的顺序
*
* @return 0
*/
@Override
public int filterOrder() {
return 0;
}
/**
* 这里可以写逻辑判断,是否要过滤,本文true,永远过滤。
*
* @return true
*/
@Override
public boolean shouldFilter() {
return true;
}
/**
* 过滤器的具体逻辑。可用很复杂,包括查sql,nosql去判断该请求到底有没有权限访问。
*
* @return null
*/
@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
log.info(String.format("%s >>> %s", request.getMethod(), request.getRequestURL().toString()));
Object accessToken = request.getParameter("token");
if (accessToken == null) {
log.warn("token is empty");
ctx.setSendZuulResponse(false);
ctx.setResponseStatusCode(401);
try {
ctx.getResponse().getWriter().write("token is empty");
} catch (Exception e) {
}
return null;
}
log.info("ok");
return null;
}
}
5、zuul的容错与回退
通过实现接口org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider
可以实现Zuul的容错与回退功能
@Component
public class MyFallbackProvider implements FallbackProvider {
@Override
public String getRoute() {
//匹配微服务名字,*表示匹配所有
return "*";
}
@Override
public ClientHttpResponse fallbackResponse() {
return null;
}
@Override
public ClientHttpResponse fallbackResponse(Throwable cause) {
return new ClientHttpResponse() {
@Override
public HttpStatus getStatusCode() throws IOException {
//当fallback时返回给调用者的状态码
return HttpStatus.OK;
}
@Override
public int getRawStatusCode() throws IOException {
return this.getStatusCode().value();
}
@Override
public String getStatusText() throws IOException {
//状态码的文本形式
return null;
}
@Override
public void close() {
}
@Override
public InputStream getBody() throws IOException {
//响应体
return new ByteArrayInputStream("default fallback".getBytes());
}
@Override
public HttpHeaders getHeaders() {
//设定headers
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.TEXT_HTML);
return headers;
}
};
}
}