路由 + 过滤 = zuul ,核心就是一系列过滤器
一、作用
前置过滤器:限流、权限过滤
后置过滤器:统计、日志
1、限流: 由于zuul充当的是api网关的角色,所以限流在很适合在上面实现,时机是请求被转发到服务之前调用,放在最前面的前置过滤器上;限流也应该放在权限拦截之前;作为限流保护防止网络攻击;如下是一种谷歌限流实现:
按照一定速率往令牌桶放置令牌,当令牌桶满了就丢掉;请求来了都要从令牌桶获取令牌,获取不到将会被拒绝,获取到了才能进行正常的转发到对应服务。
二、服务网关的要素
稳定性、高可用、高并发、性能、安全、拓展性
三、环境配置和运行
1、pom文件
<dependencies>
<!-- 需要eureka中获取服务,所以引入eureka客户端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
2、yml文件
spring:
application:
name: gateway
server:
port: 9001
eureka:
client:
# eureka服务端地址
service-url:
defaultZone: http://localhost:8761/eureka
zuul:
routes:
# 配置eureka注册中心中的order服务路由到myOrder上
order: /myOrder/**
# 设置为不过滤 cookie Authorization Set-Cookie,经过zuul的路由将会携带过来这些东西
sensitiveHeaders:
#过滤拦截下面地址,可以使用**代表任意
ignored-patterns: /**/order/test
# 全部服务都可以传递ccookie,不设置敏感头
sensitive-headers:
3、application
@SpringBootApplication
//@EnableDiscoveryClient 不需要注册也可以获取到服务
@EnableZuulProxy //开启zuul路由服务代理
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}
4、zuul自定义前置过滤器
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.apache.http.HttpStatus;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_DECORATION_FILTER_ORDER;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_TYPE;
@Component
public class MyPreFilter extends ZuulFilter {
@Override
public String filterType() {
return PRE_TYPE;
}
@Override
public int filterOrder() {
return PRE_DECORATION_FILTER_ORDER -1;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() throws ZuulException {
RequestContext context = RequestContext.getCurrentContext();
HttpServletRequest request = context.getRequest();
String token = request.getParameter("token");
if (StringUtils.isBlank(token)){
//设置不通过zuul过滤
context.setSendZuulResponse(false);
//返回没有权限401状态码
context.setResponseStatusCode(HttpStatus.SC_UNAUTHORIZED);
}
return null;
}
}
端口后第一个order是服务名称,也可在zuul中配置映射别的服务名称;
如果地址栏不包含token就会被拦截,这里就是一个简易的拦截;原理是所有的请求都将经过zuul路由,那合并在所有服务中写拦截器呢,直接在zuul上实现就可以啦。
5、自定义zuul post过滤
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletResponse;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.POST_TYPE;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.SEND_RESPONSE_FILTER_ORDER;
@Component
public class MyPostFilter extends ZuulFilter {
@Override
public String filterType() {
return POST_TYPE;
}
@Override
public int filterOrder() {
return SEND_RESPONSE_FILTER_ORDER -1;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() throws ZuulException {
RequestContext context = RequestContext.getCurrentContext();
HttpServletResponse response = context.getResponse();
//在返回头中写入信息
response.setHeader("ok","你还好么,兄弟132");
return null;
}
}
6、基于谷歌限流令牌桶实现限流
import com.google.common.util.concurrent.RateLimiter;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.exception.ZuulException;
import org.springframework.stereotype.Component;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_TYPE;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.SERVLET_DETECTION_FILTER_ORDER;
@Component
public class RateLimtFilter extends ZuulFilter {
private RateLimiter RATE_LIMIT =RateLimiter.create(100);
@Override
public String filterType() {
return PRE_TYPE;
}
@Override
public int filterOrder() {
return SERVLET_DETECTION_FILTER_ORDER -1;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() throws ZuulException {
//没获得令牌则抛异常
if(!RATE_LIMIT.tryAcquire()){
throw new RuntimeException("现在人流量大,请稍后操作.....");
}
return null;
}
}