週末にメモを取る
ZuulFilterのライフサイクル
フィルタタイプfilterType
Zuulのフィルターは、以前に使用したjavax.servlet.Filterとは異なります。javax.servlet.Filterのタイプは1つだけであり、対応する要求はurlPatternsを構成することでインターセプトできます。
Zuulには合計4種類のフィルターがあり、それぞれの種類に対応する使用シナリオがあります。
1)
リクエストがルーティングされる前にpreを呼び出すことができます。ID認証のシナリオに適用可能で、認証に合格した後、次のプロセスに進みます。
2)ルート
は、リクエストをルーティングするときに呼び出されます。これはグレースケールの公開シナリオに適しており、ルーティングが実行されようとしているときにいくつかのカスタムロジックを実行できます。
3)post
は、ルートおよびエラーフィルターの後に呼び出されます。このフィルターは、リクエストが特定のサービスにルーティングされた後に実行されます。応答ヘッダーの追加や応答ログの記録などのアプリケーションシナリオに適しています。
4)
リクエストの処理中にエラーが発生すると、エラーが呼び出されます。実行中にエラーを送信すると、エラーフィルタに入り、エラー情報を一律に記録するために使用できます。
package com.cloudyoung.zuul.filter;
import com.cloudyoung.zuul.service.RedisService;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Configuration;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_DECORATION_FILTER_ORDER;
@Configuration
public class PreFilter extends ZuulFilter {
private final String Shiro_Session="shiro:session:";
@Resource
private RedisService redisService;
private static Logger log = LoggerFactory.getLogger(PreFilter.class);
/**
* 请求前处理
* @return
*/
@Override
public String filterType() {
return "pre";
}
@Override
public int filterOrder() {
return PRE_DECORATION_FILTER_ORDER - 1;
}
/**
* 是否需要过滤 true 默认false
* @return
*/
@Override
public boolean shouldFilter() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
String requestUrl = request.getRequestURL().toString();
// 请求URL内不包含login或join则需要经过该过滤器,即执行run()
return !requestUrl.contains("login") && !requestUrl.contains("logout");
}
@Override
public Object run() throws ZuulException {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
log.info(String.format("%s 方式请求 %s", request.getMethod(), request.getRequestURL().toString()));
//获取传来的参数accessToken
// Object accessToken = request.getParameter("Authorization");
Object accessToken = request.getHeader("Authorization");
if(accessToken == null) {
log.warn("Authorization token is empty");
//过滤该请求,不往下级服务去转发请求,到此结束
ctx.setSendZuulResponse(false);
ctx.setResponseStatusCode(401);
ctx.setResponseBody("{\"result\":\"Authorization is empty!\"}");
return null;
}else if(accessToken!=null && !accessToken.equals("")){
String key = String.valueOf(accessToken);
String result = redisService.get(Shiro_Session+key);
boolean notBlank = StringUtils.isNotBlank(result);
if(notBlank){
ctx.setSendZuulResponse(true);
ctx.setResponseStatusCode(200);
//如果有token,则进行路由转发
log.info("Authorization token ok");
}else{
ctx.setSendZuulResponse(false);
ctx.setResponseStatusCode(401);
ctx.setResponseBody("{\"result\":\"Authorization is unefftive!\"}");
}
}
return null;
}
}
RequestContextを使用してパラメーターを渡す
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
/过滤该请求,不往下级服务去转发请求,到此结束
ctx.setSendZuulResponse(false);
このフィルターは、ルートに入った後にのみ要求パスをフィルターします。(api / serach /またはapi / portrait /の後のリクエストのみがフィルタリングされます)
yml構成
#添加路由前缀 api
zuul:
prefix: /api
routes:
ai-serach:
path: /serach/**
serviceId: ai-serach
ai-portrait:
path: /portrait/**
serviceId: ai-portrait
add-host-header: true #添加host头信息
sensitive-headers: #敏感头信息
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 12000 #熔断 超时时长 5000ms
#ribbon的默认超时时长:(read + connect) * 2, 必须小于hystrix的时长
ribbon:
ConnectionTimeOut: 5000 #ribbon 链接超时时长
ReadTimeout: 5000 #ribbon 读取超时时长
MaxAutoRetries: 0 #ribbon 当前服务重试次数
MaxAutoRetriesNextServer: 0 #ribbon 切换服务重试次数