网关地址重定向
1、微服务调用常见问题
常见的现象
客户端会多次请求不同的微服务,增加了客户端的复杂性。
存在跨域请求,在一定场景下处理相对复杂。
认证复杂,每个服务都需要独立认证。
难以重构,随着项目的迭代,可能需要重新划分微服务。例如,可能将多个服务合并成一个或者将一个服务拆分成多个。如果客户端直接与微服务通讯,那么重构将会很难实施。
某些微服务可能使用了防火墙/浏览器不友好的协议,直接访问会有一定困难。
使用网关优点:
易于监控。可在微服务网关收集监控数据并将其推送到外部系统进行分析。
易于认证。可在微服务网关上进行认证。然后再将请求转发到后端的微服务,而无须在每个微服务中进行认证。
减少了客户端与各个微服务之间的交互次数。
2、Zuul网关的主要作用
- 是类似于Nginx的网址重定向,但zuul的重定向的一般是整个spring cloud里在Eureka注册中心的模块。
- zuul更重要的功能为过滤请求。

3、创建zuul-server网关工程
配置zuul网关的依赖包
<!--zuul-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
<!--client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
4、zuul客户端配置
启动配置
启动类上加@EnableZuulProxy注解
@EnableZuulProxy //启用zuul代理
@SpringBootApplication
public class DmwZuulServerApplication {
public static void main(String[] args) {
SpringApplication.run(DmwZuulServerApplication.class, args);
}
}
配置application.yml文件
server:
port: 6888
spring:
application:
name: zuul-server
eureka:
client:
service-url:
defaultZone: http://${eureka.instance.hostname}:7777/eureka/
instance:
hostname: 192.168.1.1 #你本机的ip地址
zuul:
routes:
user-consumer: /user/**
dm-user-consumer: /user/** 访问192.168.1.1:6888/user/userLogin会跳转到user-consumer这个消费者去调用userLogin这个路径的控制器。
**的意思是可以匹配任何多级目录的意思。
*为单级目录。
5、启动测试
访问:
http://192.168.1.1:6888/user/userLogin
消费者被调用表示成功。
收到结果: 提供者1 登录成功
网关过滤器
1、过滤器的作用
过滤器本身并不生成请求和响应对象,它只提供过滤作用。如我们大觅网的支付功能,如果请求中不带token不允许它进入消费者。
2、zuul中的过滤器类型
- PRE Filters(前置过滤器) :当请求会路由转发到具体后端服务器前执行的过滤器,比如鉴权过滤器,日志过滤器,还有路由选择过滤器
- ROUTING Filters (路由过滤器):该过滤器作用是把请求具体转发到后端服务器上,一般是通过Apache HttpClient 或者 Netflix Ribbon把请求发送到具体的后端服务器上
- POST Filters(后置过滤器):当把请求路由到具体后端服务器后执行的过滤器;场景有添加标准http 响应头,收集一些统计数据(比如请求耗时等),写入请求结果到请求方等。
- ERROR Filters(错误过滤器):当上面任何一个类型过滤器执行出错时候执行该过滤器
3、zuul过滤器执行的步骤


4、增加过滤器
在zuul-server工程中增加过滤器
@Component
public class PreFillter extends ZuulFilter{
@Override
public String filterType() {
//设置过滤器的类型有pre、route、post、error四种
return FilterConstants.PRE_TYPE;
}
@Override
public int filterOrder() {
//定义filter的顺序,数字越小表示顺序越高,越先执行 只有同类型的顺序才有意义
return 1;
}
@Override
public boolean shouldFilter() {
//表示是否需要执行该filter,true表示执行,false表示不执行
return true;
}
//filter需要执行的具体操作 此方法返回值扩展用,暂时无效
@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest req = ctx.getRequest();
String tokenStr = req.getHeader("token");
if (null == tokenStr || "".equals(tokenStr)) {
ctx.setSendZuulResponse(false);//不执行后面的过滤器
ctx.setResponseStatusCode(401); //设置出错的代码
ctx.setResponseBody("{\"msg\":\"401........\"}");
return "access denied";
}
return "pass";
}
}
5、重启测试
用Postman工具测试如下地址:
http://localhost:6888/user/dologin
通过发送token和取消token值测试变化。


多个过滤器控制执行
1、创建多个过滤器
假设现在有三个过滤器,A、B、C,如果我输入key=1,只执行过滤器A,输入key=2执行过滤器AB,输入key=3执行过滤器ABC三个。
先在dm-gateway-zuul中创建三个过滤器,让它们类型使用Pre的类型。过滤器名称是:PreFillter、SecondFilter、ThirdFilter三个类,实现ZuulFilter接口。
第一个类PreFillter:
@Component
public class PreFillter extends ZuulFilter{
@Override
public String filterType() {
return FilterConstants.PRE_TYPE; //设置过滤器的类型
}
@Override
public int filterOrder() {
return 1; //过滤器执行的顺序 只有同类型的顺序才有意义
}
@Override
public boolean shouldFilter() {
return true; //是否启用过滤器 true表示启用
}
@Override
public Object run() {
//使用RequestContext多个过滤器之间共享数据
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest req = ctx.getRequest();
String key = req.getParameter("key");
System.out.println("access pre 1 key:"+key);
if("1".equals(key)){
ctx.setSendZuulResponse(false);
}
return null;
}
}
第二个类SecondFilter:
@Component
public class SecondFilter extends ZuulFilter {
@Override
public String filterType() {
return FilterConstants.PRE_TYPE;
}
@Override
public int filterOrder() {
return 2; //此处是2
}
@Override
public boolean shouldFilter() {
RequestContext ctx = RequestContext.getCurrentContext();
//此处不是直接返回true,如果上一个过滤器ctx.setSendZuulResponse(false);此处返回false
return ctx.sendZuulResponse();
}
@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest req = ctx.getRequest();
String key = req.getParameter("key");
System.out.println("access pre 2 key:"+key);
if("2".equals(key)){
ctx.setSendZuulResponse(false);
}
return null;
}
}
第三个类ThirdFilter:
@Component
public class ThirdFilter extends ZuulFilter {
@Override
public String filterType() {
return FilterConstants.PRE_TYPE;
}
@Override
public int filterOrder() {
return 3;//此处是3
}
@Override
public boolean shouldFilter() {
RequestContext ctx = RequestContext.getCurrentContext();
return ctx.sendZuulResponse();
}
@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest req = ctx.getRequest();
String key = req.getParameter("key");
System.out.println("access pre 3 key:"+key);
if("3".equals(key)){
ctx.setSendZuulResponse(false);
}
return null;
}
}
可以在application.yml文件中设置zuul.SecondFilter.pre.disable=true可以禁用过滤器, SecondFilter是要禁用的过滤器类名。pre是指过滤器类型。
2、重启测试
访问:
http://localhost:6888/user/dologin?key=1
控制台打印:
access pre 1 key:1
访问:
http://localhost:7600/user/userLogin?key=2
控制台打印:
access pre 1 key:2
access pre 2 key:2
