导包
SpringBoot和SpringCloud的依赖就不提及了,相信你自己都导入了,注意版本对应关系
代码语言:javascript复制 <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的注解
代码语言:javascript复制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);
}
}
编写配置文件
代码语言:javascript复制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个最重要的方法:
代码语言:javascript复制public abstract ZuulFilter implements IZuulFilter{
abstract public String filterType(); // 类型 前置 路由中 路由后 error类型
abstract public int filterOrder(); // 过滤器的执行顺序 这个返回值越小就越先执行
boolean shouldFilter();// 来自IZuulFilter 是否要进入到run方法中
Object run() throws ZuulException;// IZuulFilter 核心方法
}
以上方法和其他方法:
-
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;
@Component
public 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: 6000
ribbon:
ConnectTimeout: 1000 # 连接超时时长
ReadTimeout: 2000 # 数据通信超时时长
MaxAutoRetries: 0 # 当前服务器的重试次数
MaxAutoRetriesNextServer: 1 # 重试多少次服务,连接的服务如果有集群可以多写几个,可以找到另一个服务,但注意超时时间