(一)zuul(智能路由,网关)过滤器:
@Component
public class AccessFilter extends ZuulFilter {
private static final Logger logger = LoggerFactory.getLogger(AccessFilter.class);
//初始化 放入 5令牌/s 时间窗口为 1s
private final RateLimiter rateLimiter = RateLimiter.create(5.0);
//声明zuul的路由次数 为了累计数量!
private int zuulTimes;
@Autowired
private StringRedisTemplate stringRedisTemplate;
/**
* 返回boolean类型。代表当前filter是否生效。
* 默认值为false。
* 返回true代表开启filter。
*/
@Override
public boolean shouldFilter() {
return true;
}
/**
* zuul用redis存储限流次数满足后提示信息!!! 这个是利用redis来做,而不是用zuul的限流来做的
*
*
* run方法就是过滤器的具体逻辑。
* return 可以返回任意的对象,当前实现忽略。(spring-cloud-zuul官方解释)
* 直接返回null即可。
*/
/*@Override
public Object run() throws ZuulException {
*//* zuulTimes++;
// final RequestContext ctx = RequestContext.getCurrentContext();
// ctx.addZuulRequestHeader("ZUUL WARN", "zuul限流三次,请注意超过"++"次");
// Map<String, String> zuulRequestHeaders = ctx.getZuulRequestHeaders();
if (zuulTimes > 3){
Map<String, String> mapzuul = new HashMap<>(1);
mapzuul.put("ZUUL WARN", "zuul限流三次,请注意,已经超过"+String.valueOf(zuulTimes-1)+"次");
stringRedisTemplate.opsForHash().putAll("ZUUL限流",mapzuul);
// logger.info("zuul 限流三次,请注意不要继续发送请求了!!!!");
}*//*
return null;
}*/
/**
* @Author LJ
* @Description 过滤器的具体执行逻辑。 https://www.jianshu.com/p/8f548e469bbe
* @Date 18:48 2020/3/2
* @Param []
* @return java.lang.Object
**/
@Override
public Object run() throws ZuulException {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletResponse response = ctx.getResponse();
//如果该许可可以在无延迟下的情况下立即获取得到的话,当你手速快的情下会有所延迟。
if(!rateLimiter.tryAcquire()) {
response.setContentType(MediaType.TEXT_PLAIN_VALUE);
response.setStatus(HttpStatus.TOO_MANY_REQUESTS.value());
ctx.setSendZuulResponse(false);// 过滤该请求,不对其进行路由
try {
//会输出在浏览器上
response.getWriter().write("TOO MANY REQUESTS");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else {
ctx.setResponseStatusCode(200);
logger.info("OK !!!");
}
return null;
}
/**
* 过滤器的类型。可选值有:
* pre - 前置过滤
* route - 路由后过滤
* error - 异常过滤
* post - 远程服务调用后过滤
*/
@Override
public String filterType() {
return "pre";
}
/**
* 同种类的过滤器的执行顺序。
* 按照返回值的自然升序执行。
*/
@Override
public int filterOrder() {
return 0;
}
}
这个类可以在run()中添加一些过滤条件起到过滤作用。这个类当你请求的时候会先加入这个类的run()中。
(二)服务降级:
当我们的zuul进行路由分发时,如果后端服务没有启动,
或者调用超时,这时候我们希望Zuul提供一种降级功能,而不是将异常暴露出来。
package com.springcloud.zuul.config;
/**
* @Classname MyfaultFallback
* @Description 服务降级 https://www.cnblogs.com/-flq/p/11970294.html
* 服务降级,当服务器压力剧增的情况下,根据当前业务情况及流量对一些服务和页面有策略的降级,以此释放服务器资源以保证核心任务的正常运行
* @Date 2020/3/2 21:50
* @Created by Administrator
*/
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import javax.servlet.http.HttpServletRequest;
import com.netflix.hystrix.exception.HystrixTimeoutException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Component;
import com.netflix.zuul.context.RequestContext;
/**
* @Author LJ
* @Description 服务降级(给任何一个服务降级都可以)其实和熔断器中生产者挂了有点类似。
*
* 当我们的zuul进行路由分发时,如果后端服务没有启动,
* 或者调用超时,这时候我们希望Zuul提供一种降级功能,而不是将异常暴露出来。
* @Date 22:14 2020/3/2
* @Param
* @return
**/
@Component
class MyFallbackProvider implements FallbackProvider {
/**
* 设置当前是给哪个服务开启fallback,返回值就是服务的名字,如果是给所有的,返回*
* @return
*/
@Override
public String getRoute() {
return "*";
}
/**
* 当出现问题的时候返回给调用者具体的返回内容
* @param route 返回给哪个service
* @param cause 出现的异常
* @return
*/
@Override
public ClientHttpResponse fallbackResponse(String route, final Throwable cause) {
if (cause instanceof HystrixTimeoutException) {
return response(HttpStatus.GATEWAY_TIMEOUT);
} else {
return response(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
private ClientHttpResponse response(final HttpStatus status) {
return new ClientHttpResponse() {
@Override
public HttpStatus getStatusCode() throws IOException {
return status;
}
@Override
public int getRawStatusCode() throws IOException {
return status.value();
}
@Override
public String getStatusText() throws IOException {
return status.getReasonPhrase();
}
@Override
public void close() {
}
/**
* 响应正文
* @return
* @throws IOException
*/
@Override
public InputStream getBody() throws IOException {
return new ByteArrayInputStream("某一服务出问题了".getBytes());
}
/**
* 响应头
* @return
* @throws IOException
*/
@Override
public HttpHeaders getHeaders() {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
return headers;
}
};
}
}