一 什么是网关服务
1、为社么要使用网关服务
2 网关解决了什么问题
二 网关入门案例
1 创建项目,修改pom文件
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zuul</artifactId>
</dependency>
2 修改配置文件
spring.application.name=zuul-gateway
server.port=9010
#设置服务注册中心地址,指向另一个注册中心
eureka.client.serviceUrl.defaultZone=http://eureka1:8080/eureka/,http://eureka2:9090/eureka/
3 修改启动类
/@SpringBootApplication
@EnableZuulProxy
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
}
4 访问服务测试
http://网关服务地址:网关服务端口/访问的服务的名称/访问的服务中的接口的地址
三 Zuul路由规则
1 url指定路由规则
1.1 创建项目,修改pom文件
1.2 修改配置文件
spring.application.name=zuul-gateway
server.port=9010
#设置服务注册中心地址,指向另一个注册中心
eureka.client.serviceUrl.defaultZone=http://eureka1:8080/eureka/,http://eureka2:9090/eureka/
# 1 ###################### 路由指定:URL 指定 #############################
# URL 匹配关键字,如果包含关键字就跳转到指定的 URL 中
zuul.routes.e-book-product-provider.path=/ego-book-product-provider/**
zuul.routes.e-book-product-provider.url=http://127.0.0.1:9001/
1.3 修改启动类
1.4 通配符含义
2 采用服务名称指定路由方式
## 2 ###################### 路由指定:服务指定 1 #############################
##将路径的/suibian/引到 eureka 的 e-book-product-provider 服务 上
##规则:zuul.routes.路径名.path
##规则:zuul.routes.路径名.serviceId=eureka 的服务名
#zuul.routes.e-book-product-provider.path=/suibian/**
#zuul.routes.e-book-product-provider.serviceId=e-book-product-provider
## 3 ###################### 路由指定:服务指定 2 #############################
#zuul.routes 后面跟着的是服务名,服务名后面跟着的是路径规则,这种 配置方式更简单。
zuul.routes 后面跟着的是服务名必须与provider的服务名一致
zuul.routes.e-book-product-provider.path=/suibian/**
3 路由的排除方法
3.1 排除指定的某几个服务
## 4 ###################### 路由排除:排除某几个服务 ############################# ##排除后,这个地址将为空 http://127.0.0.1:9030/e-book-product-provider/product/findAll
## 多个服务逗号隔开
#zuul.ignored-services=e-book-product-provider
3.2 排除所有服务,在开放某几个服务
## 5 ###################### 路由排除:排除所有服务 #############################
#由于服务太多,不可能手工一个个加,故路由排除所有服务,然后针对要 路由的服务进行手工加
#zuul.ignored-services=*
#zuul.routes.e-book-order-provider.path=/e-book-order-provi der/**
3.3 排除关键字
## 6 ###################### 路由排除:排除指定关键字的路径 #############################
# 排除所有包括/list/的路径
zuul.ignored-patterns=/**/findAll/**
zuul.routes.ego-book-order-provider.path=/suibian/**
4 路由的添加前缀的方法
访问服务的url必须加上前缀
## http://127.0.0.1:9030/suibian/product-provider/product/findAll
zuul.prefix=/suibian
zuul.routes.e-book-product-provider.path=/product-provider/ **
四 网关过滤器
1 自定义网关过滤器
1 创建项目,添加zuul依赖
2 修改配置文件
3 修改启动类
/@SpringBootApplication
@EnableZuulProxy
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
}
4 编写拦截器
/@Component
public class LogFilter extends ZuulFilter{
private static Logger logger = org.slf4j.LoggerFactory.getLogger(LogFilter.class);
//是否开启拦截器,默认是false
@Override
public boolean shouldFilter() {
// TODO Auto-generated method stub
return true;
}
//过滤内容:在run方法编写过滤逻辑
@Override
public Object run() {
//获取上下文对象
RequestContext currentContext = RequestContext.getCurrentContext();
HttpServletRequest request = currentContext.getRequest();
logger.info("LogFilter......method={},url={}",request.getMethod(),request.getRequestURI().toString());
return null;
}
//过滤器类型通过过滤器类型决定了过滤器执行的时间
@Override
public String filterType() {
// TODO Auto-generated method stub
return "pre";
}
//过滤器的执行顺序:通过整数表示顺序,数值越小,优先级越高
@Override
public int filterOrder() {
// TODO Auto-generated method stub
return 0;
}
}
2 过滤器类型与生命周期
2.1 Zuul过滤器类型
2.2 Zuul生命周期
3 网关过滤器实现权限验证
需求:在网关过滤器中通过 Token 判断用户是否登录
3.1 创建项目,修改pom文件添加zuul坐标
3.2 修改配置文件
3.3 创建AccessFilter
/@Component
public class LogFilter extends ZuulFilter{
private static Logger logger = org.slf4j.LoggerFactory.getLogger(LogFilter.class);
//是否开启拦截器,默认是false
@Override
public boolean shouldFilter() {
// TODO Auto-generated method stub
return true;
}
//过滤内容:在run方法编写过滤逻辑
@Override
public Object run() {
//获取上下文对象
RequestContext cc = RequestContext.getCurrentContext();
HttpServletRequest request = cc.getRequest();
//从表单中获取token
String token = request.getParameter("token");
if(token == null) {
logger.warn("tokne is null........");
cc.setSendZuulResponse(true);//代表请求结束,不再继续向下执行
cc.setResponseStatusCode(401);//设置响应状态吗
cc.setResponseBody("{"result": "token is null...."}");//相应内容
cc.getResponse().setContentType("text/html;charset=utf-8"); //响应类型
}else {
//访问 redis 服务 进行验证
logger.info("token is OK");
}
return null;
}
//过滤器类型通过过滤器类型决定了过滤器执行的时间
@Override
public String filterType() {
// TODO Auto-generated method stub
return "pre";
}
//过滤器的执行顺序:通过整数表示顺序,数值越小,优先级越高
@Override
public int filterOrder() {
// TODO Auto-generated method stub
return 0;
}
}
3.4 编写启动类
4 网关过滤器实现异常统一处理
1 创建ErrorFilter
/@Component
public class ErrorFilter extends ZuulFilter{
private static Logger logger = org.slf4j.LoggerFactory.getLogger(ErrorFilter.class);
//是否开启拦截器,默认是false
@Override
public boolean shouldFilter() {
// TODO Auto-generated method stub
return true;
}
//过滤内容:在run方法编写过滤逻辑
@Override
public Object run() {
logger.info("-----------ErrorFilter----------------");
return null;
}
//过滤器类型通过过滤器类型决定了过滤器执行的时间
@Override
public String filterType() {
// TODO Auto-generated method stub
return "error";
}
//过滤器的执行顺序:通过整数表示顺序,数值越小,优先级越高
@Override
public int filterOrder() {
// TODO Auto-generated method stub
return 0;
}
2 执行顺序
3 创建一场相应的过滤器
/@RestController
public class ExceptionHandler implements ErrorController {
@Override
public String getErrorPath() {
return "/error";
}
@RequestMapping("/error")
public String error() {
return "{"error":"网络异常,请联系管理员,电话:120"}";
}
}
五 网关容错
1 zuul 和 hystrix 无缝结合
在 zuul 的 jar 包中包含了 hystrix 的 jar 包。所以我们不需要在项目中添加 Hystrix 的坐标
1.1 访问网关服务的数据监控流
1.2 启动 dashboard-view 服务通过可视化界面查看监控数据
2 在网关中实现对服务降级处理
如果需要对多个服务进行降级,需要编写多个类
2.1 创建项目,添加zuul依赖
2.2 修改配置文件
2.3 添加 ProviderProductFallback 类
/**
* 对provider服务进行降级处理
* @author 18722
*
*/
@Component
public class ProductProviderFallback implements ZuulFallbackProvider{
/**
* 给定对那个服务进行降级
*/
@Override
public String getRoute() {
// TODO Auto-generated method stub
return "ego-book-product-provider";
}
/**
* 当服务无法执行时返回托底数据的方法
*/
@Override
public ClientHttpResponse fallbackResponse() {
ClientHttpResponse cr = new ClientHttpResponse() {
//设置响应头信息
@Override
public HttpHeaders getHeaders() {
HttpHeaders header = new HttpHeaders();
MediaType mediaType = new MediaType("application","json",Charset.forName("utf-8"));
header.setContentType(mediaType );
return header;
}
//设置响应体信息
@Override
public InputStream getBody() throws IOException {
String reponse = "商品服务不可用,请联系管理员,电话110";
return new ByteArrayInputStream(reponse.getBytes());
}
// ClientHttpResponse 的 fallback 的状态码 返回 String
@Override
public String getStatusText() throws IOException {
// 调用getStatusCode将httpStatus转换为String
return this.getStatusCode().getReasonPhrase();
}
// ClientHttpResponse 的 fallback 的状态码 返回 HttpStatus
@Override
public HttpStatus getStatusCode() throws IOException {
return HttpStatus.OK;
}
// ClientHttpResponse 的 fallback 的状态码 返回 int
@Override
public int getRawStatusCode() throws IOException {
//调用getStatusCode将httpStatus转换为int
return this.getStatusCode().value();
}
@Override
public void close() {
// TODO Auto-generated method stub
}
};
return cr;
}
六 网关限流实现自我保护
1 创建项目,修改pom'文件
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zuul</artifactId>
</dependency>
<dependency>
<groupId>com.marcosbarbero.cloud</groupId>
<artifactId>spring-cloud-zuul-ratelimit</artifactId>
<version>1.3.4.RELEASE</version>
</dependency>
2 修改配置文件实现限流
2.1 全局限流
spring.application.name=zuul-gateway-ratelimit
server.port=9010
#设置服务注册中心地址,指向另一个注册中心
eureka.client.serviceUrl.defaultZone=http://eureka1:8080/eureka/,http://eureka2:9090/eureka/
#全局配置限流
zuul.ratelimit.enabled=true
##60s 内请求超过 3 次,服务端就抛出异常,60s 后可以恢复正常请求
zuul.ratelimit.default-policy.limit=3
zuul.ratelimit.default-policy.refresh-interval=60
##针对 IP 进行限流,不影响其他 IP
zuul.ratelimit.default-policy.type=origin
测试 当当问第四下时,抛出异常
2.2 局部限流
# 局部限流:针对某个服务进行限流
##开启限流
#zuul.ratelimit.enabled=true
##60s 内请求超过 3 次,服务端就抛出异常,60s 后可以恢复正常请求
#zuul.ratelimit.policies.ego-book-product-provider.limit=3
#zuul.ratelimit.policies.ego-book-product-provider.refresh-interval=60
##针对某个 IP 进行限流,不影响其他 IP
#zuul.ratelimit.policies.e-book-product-provider.type=origin
3 网关限流参数
七 Zuul两层性能调优
1 超时优化图解
Zuul底层采用了hystrix和ribbon来进行通信
当Zuul启动之后hystrix就有一个线程池,请求网关的线程都会进入到hystrix中,hystrix在根据网关中请求的路由规则的
处理,开启一个新的线程通过ribbon调用问我们的服务
** ribbon的超时时间要小于hystrix的超市时间,如果大于,当真正的有超时异常发生,不管ribbon调用有没有完成
hystrix之间返回超时异常,假如hystrix的超时时间为10,ribbon的超时时间为2,ribbon超时,但是hystrix
的线程没有超时,ribbon就会拿着这个线程接着请求集群中的其他节点,直到htstrix的线程池超时,这是才是真正的超时
2 案例演示
2.1 创建项目,添加Zuul依赖
2.2 修改配置文件
spring.application.name=zuul-gateway-timeout
server.port=9010
#设置服务注册中心地址,指向另一个注册中心
eureka.client.serviceUrl.defaultZone=http://eureka1:8080/eureka/,http://eureka2:9090/eureka/
#第一层 hystrix 超时时间设置 #默认情况下是线程池隔离,超时时间 1000ms
hystrix.command.default.execution.isolation.thread.timeoutI nMilliseconds=8000
#第二层 ribbon 超时时间设置:设置比第一层小 # 请求连接的超时时间: 默认 5s
ribbon.ConnectTimeout=5000
# 请求处理的超时时间: 默认 5s
ribbon.ReadTimeout=5000