快速入门
新建zuul-gateway工程,引入pom依赖
org.springframework.cloud
spring-cloud-starter-netflix-zuul
org.springframework.cloud
spring-cloud-starter-netflix-eureka-client
引导类标注
@EnableZuulProxy
@EnableDiscoveryClient
@SpringBootApplication
public class ZuulGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulGatewayApplication.class, args);
}
}
基于服务发现配置路由规则
zuul.routes.feign.path=/feign/**
zuul.routes.feign.service-id=feign-consumer
zuul.routes.hello.path=/hello/**
zuul.routes.hello.service-id=hello-service
请求过滤
实现ZuulFilter接口,如果请求内容中没有token,则返回401
@Slf4j
public class AccessFilter extends ZuulFilter {
@Override
public String filterType() { //过滤器类型,这里为pre,标识会在请求被路由之前执行
return "pre";
}
@Override
public int filterOrder() { //过滤器的执行顺序
return 0;
}
@Override
public boolean shouldFilter() { //过滤是否会被执行,在应用中可以根据业务需求自定义实现
return true;
}
@Override
public Object run() throws ZuulException { //过滤器具体逻辑
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
log.info("filter..........");
Object t = request.getParameter("token");
if(Objects.isNull(t)) {
ctx.setSendZuulResponse(false);
ctx.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
}
return null;
}
}
注入filter实例
@Bean
ZuulFilter filter() {
return new AccessFilter();
}
路由详解
不依赖于服务治理,单实例配置,通过参数对配置
zuul.routes..path=/feign/**
zuul.routes..service-id=http://localhost:8080
多实例配置
zuul.routes..path=/feign/**
zuul.routes..service-id=MyService
#默认依赖服务发现机制获取服务名对应的实例清单,没有整合eureka,所以需要设置为false
ribbon.eureka.enabled=false
MyService.ribbon.listOfServers=http://localhost:8080,http://localhost:8081
服务路由的默认规则
在实际应用中,大部分的路由配置几乎都会采用服务名作为请求前缀,对于这种有规则的配置内容,在引入eureka后,zuul会自动创建一个默认路由规则,这个默认规则的path会使用serviceId作为请求前缀
在配置文件中注释掉自定义路由规则
#zuul.routes.feign.path=/feign/**
#zuul.routes.feign.service-id=feign-consumer
直接使用serviceId作为请求前缀发起请求,也可以实现正常访问
http://localhost:8084/
自定义路由规则
可以使用正则表达式自定义路由规则
@Bean
PatternServiceRouteMapper patternServiceRouteMapper() {
return new PatternServiceRouteMapper("","");
}
- 参数一检查服务名称是否匹配正则表达式
- 参数二根据服务名定义的内容转换出的路径表达式
路径匹配
采用ant表达式风格,即?//*,这里需要注意的是,路由的保存是有序的,而通过properties文件加载是无序的,可以通过yaml文件来实现有序的路由规则
zuul:
routes:
feign:
path: /feign/**
service-id: feign-consumer
hello:
path: /hello/**
service-id: hello-service
忽略表达式
通过ignored-patterns可以设置不希望被网关路由的url表达式
zuul.ignored-patterns=/**/hello/*
路由前缀
为网关路由规则增加/api前缀
zuul.prefix=/api
本地跳转
zuul支持forward形式的服务端跳转配置,下面的配置实现了hello跳转到网关/local/hello的功能
zuul.routes.hello.path=/hello/**
zuul.routes.hello.service-id=forward:/local
Cookie和头信息
默认情况下,zuul在请求路由时,会过滤掉http请求头中的一些敏感信息,防止被传递到下游服务器,如Cookie,Authorization,Set-Cookie,但是如果使用了spring security,shrio等安全框架时,需要使用这些敏感信息,可以通过以下两种方式进行配置
全局配置
zuul.sensitive-headers=
指定路由配置
设置敏感头为空
zuul.routes..sensitive-headers=
或开启自定义敏感头
zuul.routes..custom-sensitive-headers=true
在使用安全框架时,登录成功后,会返回302,location指向的是具体的服务地址,而不是网关,可以设置
zuul.add-host-header=true
这样,使得网关在进行路由转发钱设置Host头信息,标识最初的服务器请求地址
Hystrix和ribbon支持
在spring-cloud-starter-netflix-zuul中已经引入了hystrix和ribbon支持,可以设置ribbon及hystrix的相关配置
org.springframework.cloud
spring-cloud-starter-netflix-hystrix
2.2.2.RELEASE
compile
org.springframework.cloud
spring-cloud-starter-netflix-ribbon
2.2.2.RELEASE
compile
过滤器详解
zuul中过滤器是实现请求转发最关键的核心部件,每一个进入zuul的http请求都会经过一些列的过滤器处理链得到请求响应并返回给客户端
zuul中实现的过滤器包含四个基本特征,过滤类型,执行顺序,执行条件,具体操作,实际上就是ZuulFilter中定义的四个抽象方法
public class AccessFilter extends ZuulFilter {
@Override
public String filterType() { //过滤器类型,这里为pre,标识会在请求被路由之前执行
return "pre";
}
@Override
public int filterOrder() { //过滤器的执行顺序
return 0;
}
@Override
public boolean shouldFilter() { //过滤是否会被执行,在应用中可以根据业务需求自定义实现
return true;
}
@Override
public Object run() throws ZuulException { //过滤器具体逻辑
}
}
zuul中,过滤器类型的执行顺序为
pre(customer) -> routing -> post -> error
其中error只有在前序三种过滤器发生错误时才会执行
核心过滤器
zuul中定义了一批核心过滤器位于org.springframework.cloud.netflix.zuul.filters包下
pre阶段
- ServletDetectionFilter:用来检查是通过spring的dispatcherServlet处理运行的还是通过ZuulServlet来处理运行的,它的检测结果会保存到当前请求上下文的isDispaterServletRequest参数中
- Servlet30WrapperFilter:执行顺序-2,将原始的httpservletequest包装成servelt30requestwrapper对象
- FormBodyWrapperFilter:执行顺序-1,仅对两类请求生效,application/x-www-form-urlencoded和multipart/form-data,将该两类请求包装成FormBodyRequestWrapper
- DebugFilter:执行顺序1,根据zuul.debug.request和请求中的debug参数决定是否执行过滤器中操作。具体操作则是把debugRouting和debugRequest参数设置为true,在同一个请求的不同生命周期中都可以访问这两个参数,当环境出现问题时,可以通过参数请求方式激活debug分析信息
- PreDecorationFilter:执行顺序5,pre阶段最后执行的过滤器,为当前请求设置做预处理
route过滤器
- RibbonRoutingFilter:执行顺序10,只对配置serviceId路由规则的请求生效,通过ribbon和hystrix来向服务实例发起请求
- SimpleHostRoutingFilter:执行顺序100,只对配置url路由规则的请求生效
- SendForwardFilter:执行顺序500,处理路由配置中forward本地跳转
post过滤器
- SendErrorFilter:执行顺序0,将请求上下文中的错误信息来组成一个forward到api网关/error错误端点产生错误响应
- SendResponseFilter:执行顺序1000,利用请求上下文组织需要发送会客户端的响应内容
异常处理
使用errorfilter自定义异常处理,流转到SendErrorFilter
@Slf4j
public class ErrorFilter extends ZuulFilter {
@Override
public String filterType() { //过滤器类型,这里为pre,标识会在请求被路由之前执行
return "error";
}
@Override
public int filterOrder() { //过滤器的执行顺序
return 10;
}
@Override
public boolean shouldFilter() { //过滤是否会被执行,在应用中可以根据业务需求自定义实现
return true;
}
@Override
public Object run() throws ZuulException { //过滤器具体逻辑
RequestContext ctx = RequestContext.getCurrentContext();
Throwable t = ctx.getThrowable();
log.info("filter..........");
ctx.set("error.status_code",HttpStatus.BAD_GATEWAY.value());
ctx.set("error.exception",t.getCause());
return null;
}
}