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/方法地址,测试
完成上面的操作可以用前缀+服务名称+服务地址访问,但有一个问题,加上api就可以直接访问服务的方法,这样是不安全的,所有要用到了Zuul的过滤器ZuulFilter ZuulFilter是过滤器的顶级父类,这里看一下其中定义的4个最重要的方法:
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 # 重试多少次服务,连接的服务如果有集群可以多写几个,可以找到另一个服务,但注意超时时间