zuul网关的使用
依赖
<!--网关的依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>配置信息
#服务的名称
spring:
application:
name: zuul-gateway
zuul:
routes:
#服务名 : 修改后的服务别名 服务之间的名称不能重复否则会覆盖
order-service: /order/**
product-service: /product/**
#忽略整个服务,不对外提供接口。但是可以通过路由的配置访问,可以通过/*-service/**过滤所有的服务,只能通过路由配置的别名访问
# ignored-services: order-service
ignored-services: /*-service/**
#网关默认会把header的cookie、Set-Cookie、Authorization这三个参数过滤
sensitive-headers:启动类增加注解
在启动类当中增加注解@EnableZuulProxy(包含了@EnableCircuitBreaker,默认集成断路器),开启zuul网关的代理。
通过网关访问服务
通过网关的服务必须都是在一个注册中心下。如果没有在配置文件对服务名进行一个别名修改,则调用规则如下:
http://ip:网关port/服务名/url,如:localhost:9000/order-service/saveProductOrder
通过配置文件修改了服务别名,将order-service修改成order,调用地址如下:
localhost:9000/order/saveProductOrder
http请求过滤
zuul的配置类是在ZuulProperties当中。http的请求的头部参数中,网关默认会把header的敏感信息cookie、Set-Cookie、Authorization这三个参数过滤, 如果网络权限是根据cookie获取权限的,需要在配置文件开放。
zuul:
#网关默认会把header的cookie、Set-Cookie、Authorization这三个参数过滤
sensitive-headers:自定义过滤器
新建一个继承ZuulFilter的类,并且实现。在类的顶部增加@component让spring能够扫描。
zuul过滤主要有几种,前置过滤器(请求过滤)、路由过滤器(转发到源服务地址)、后置过滤器(结果过滤)和error过滤器(错误信息过滤)。
具体实现如下:
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpStatus;
import org.springframework.stereotype.Component;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_TYPE;
/**
* @Description TODO
* @Author lcy
* @Date 2020/5/1 14:01
*/
@Component
public class LoginFilter extends ZuulFilter {
/**
* FilterConstants包含以下四种过来类型
* ERROR_TYPE = "error"; 错误过滤器
* POST_TYPE = "post"; 后置过滤器
* PRE_TYPE = "pre"; 前置过滤器
* ROUTE_TYPE = "route"; 路由过滤器
* @return java.lang.String
**/
@Override public String filterType(){
return PRE_TYPE;
}
/**
* 过滤器执行顺序,过滤器的order值越小,越先执行。但是不能早于servlet过滤器等,在FilterConstants中搜索ORDER
* 或者找到PRE_DECORATION_FILTER_ORDER(执行前置的顺序)。根据需求进行选择
* @return int
**/
@Override public int filterOrder(){
return 4;
}
/**
* 过滤器是否生效 可以根据业务需求进行过滤
* @return boolean
**/
@Override public boolean shouldFilter(){
//获取请求上下文对象
RequestContext currentContext = RequestContext.getCurrentContext();
//获取请求的对象
HttpServletRequest request = currentContext.getRequest();
//根据url决定是否生效
return "/order/saveProductOrder".equalsIgnoreCase(request.getRequestURI());
}
/**
* 拦截内容
* @return java.lang.Object
**/
@Override public Object run() throws ZuulException{
//获取请求上下文对象
RequestContext currentContext = RequestContext.getCurrentContext();
//获取请求的对象
HttpServletRequest request = currentContext.getRequest();
//获取token
String headerToken = request.getHeader("token");
String paramToken = request.getParameter("token");
//判断token是否为空
if (StringUtils.isBlank(headerToken) && StringUtils.isBlank(paramToken)) {
//直接返回
currentContext.setSendZuulResponse(false);
//返回的状态码 从HttpStatus类获取
currentContext.setResponseStatusCode(HttpStatus.SC_UNAUTHORIZED);
}
return null;
}
}通过谷歌guava框架进行限流
import javax.servlet.http.HttpServletRequest;
import org.apache.http.HttpStatus;
import org.springframework.stereotype.Component;
import com.google.common.util.concurrent.RateLimiter;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_TYPE;
/**
* @Description 限流
* @Author lcy
* @Date 2020/5/1 15:01
*/
@Component
public class RateLimiterFilter extends ZuulFilter {
/** 限流的类 每秒产生1000个令牌,即限流1000 */
private static final RateLimiter RATE_LIMITER = RateLimiter.create(1000);
@Override public String filterType(){
return PRE_TYPE;
}
@Override public int filterOrder(){
return -4;
}
@Override public boolean shouldFilter(){
//获取请求上下文对象
RequestContext currentContext = RequestContext.getCurrentContext();
//获取请求的对象
HttpServletRequest request = currentContext.getRequest();
//根据url决定是否生效
return "/order/saveProductOrder".equalsIgnoreCase(request.getRequestURI());
}
@Override public Object run() throws ZuulException{
//获取请求上下文对象
RequestContext currentContext = RequestContext.getCurrentContext();
if(!RATE_LIMITER.tryAcquire()){
//直接返回
currentContext.setSendZuulResponse(false);
//返回的状态码 从HttpStatus类获取
currentContext.setResponseStatusCode(HttpStatus.SC_REQUEST_TIMEOUT);
}
return null;
}
}网关集群
在用户访问网关之前,最好使用nginx+lvs+keepalive的反向代理,对网关的集群进行代理和转发
zuul集群只需要多启动几个应用同时注册在注册中心。
