SpringBoot和SpringCloud的依赖就不提及了,相信你自己都导入了,注意版本对应关系
<dependencies><!-- zuul--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-zuul</artifactId> </dependency><!-- eureka-client--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> </dependencies> 启动类添加 @EnableZuulProxy 注解和Eureka的注解 import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.cloud.netflix.zuul.EnableZuulProxy;@SpringBootApplication@EnableZuulProxy //开启Zuul的网关功能@EnableDiscoveryClient //开启Eureka客户端发现功能public class ZuulApplication { public static void main(String[] args) { SpringApplication.run(ZuulApplication.class,args); }} 编写配置文件 server: port: 10010 #服务端口spring: application: name: api-gateway #指定服务名zuul: #混淆写法,也是最简洁的写法 ignored-services: - eureka-server# Eureka的服务名称 prefix: /api#添加的前缀eureka: client: service-url: defaultZone: http://127.0.0.1:10086/eureka访问 http://localhost:10010/api/user-consumer/方法地址,测试
Zuul的过滤器使用完成上面的操作可以用前缀+服务名称+服务地址访问,但有一个问题,加上api就可以直接访问服务的方法,这样是不安全的,所有要用到了Zuul的过滤器ZuulFilter
ZuulFilter是过滤器的顶级父类,这里看一下其中定义的4个最重要的方法:
以上方法和其他方法:
filterType方法:返回字符串,代表过滤器的类型。包含以下4种:
pre方法:请求在被路由之前执行
route方法:在路由请求时调用
post方法:在routing和errror过滤器之后调用
error方法:处理请求时发生错误调用
filterOrder方法:通过返回的int值来定义过滤器的执行顺序,数字越小优先级越高
shouldFilter方法:返回一个Boolean值,判断该过滤器是否需要执行。返回true执行,返回false不执行
run方法:过滤器的具体业务逻辑
自定义过滤器新建一个包:filters 包里新建一个类并extends ZuulFilter类并重写方法
案例:
必须传来一个 access-token 参数,没有就返回一个401状态码
import com.netflix.zuul.ZuulFilter;import com.netflix.zuul.context.RequestContext;import com.netflix.zuul.exception.ZuulException;import org.apache.commons.lang.StringUtils;import org.springframework.http.HttpStatus;import org.springframework.stereotype.Component;import javax.servlet.http.HttpServletRequest;import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.FORM_BODY_WRAPPER_FILTER_ORDER;import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_TYPE;@Componentpublic class LoginFilter extends ZuulFilter { @Override public String filterType() { return PRE_TYPE; } @Override public int filterOrder() { return FORM_BODY_WRAPPER_FILTER_ORDER-1; } @Override public boolean shouldFilter() { return true; } @Override public Object run() throws ZuulException { // 获取请求上下文 RequestContext ctx = RequestContext.getCurrentContext(); // 获取request对象 HttpServletRequest request = ctx.getRequest(); // 获取请求参数 String token = request.getParameter("access-token"); // 判断是否存在 if(StringUtils.isBlank(token)){ // 不存在,未登录,拦截 ctx.setSendZuulResponse(false); // 设置返回状态码 ctx.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value()); } return null; // 什么都不做 直接进入到微服务中 }}测试一下,没有access-token 是进不去的
负载均衡和熔断Zuul中默认就已经集成了Ribbon负载均衡和Hystix熔断机制。但是所有的超时策略都是走的默认值,比如熔断超时时间只有1S,很容易就触发了。因此建议我们手动在配置文件加上:
hystrix: command: default: execution: isolation: thread: timeoutInMilliseconds: 6000ribbon: ConnectTimeout: 1000 # 连接超时时长 ReadTimeout: 2000 # 数据通信超时时长 MaxAutoRetries: 0 # 当前服务器的重试次数 MaxAutoRetriesNextServer: 1 # 重试多少次服务,连接的服务如果有集群可以多写几个,可以找到另一个服务,但注意超时时间