Zuul作為網關服務,是其他各服務對外中轉站,通過Zuul進行請求轉發。這就涉及到部分資料是不能原封傳回的,比如服務之間通信的憑證,使用者的加密資訊等等。
需要JAVA Spring Cloud大型企業分布式微服務雲建構的B2B2C電子商務平台源碼 一零三八七七四六二六
舉個例子,使用者服務提供一個登入接口,使用者名密碼正确後傳回一個Token,此Token作為使用者服務的通行證,那麼使用者登入成功後傳回的Token就需要進行加密或者防止篡改處理。在到達使用者服務其他接口前,就需要對Token進行校驗,非法的Token就不需要轉發到使用者服務中了,直接在網關層傳回資訊即可。
要修改服務傳回的資訊,需要使用的是Zuul的過濾器。使用時隻需要繼承ZuulFilter,實作必要的方法即可。
Zuul提供預設的四種過濾器類型,通過filterType方法進行辨別
pre:可以在請求被路由之前調用
route:在路由請求時候被調用
post:在route和error過濾器之後被調用
error:處理請求時發生錯誤時被調用
過濾器執行的順序是通過filterOrder方法進行排序,越小的值越優先處理。FilterConstants定義了一些列預設的過濾器的執行順序和路由類型,大部分需要用到的常量都在這兒。
例子中說明的,隻有登入接口需要攔截,是以隻需要攔截登入請求(/user/login)即可。可以通過過濾器的shouldFilter方法進行判斷是否需要攔截。
由于是在準發使用者服務成功後進行的資料修改,是以攔截器的類型時post類型的。整個類的實作如下:
public class AuthResponseFilter extends AbstractZuulFilter {
private static final String RESPONSE_KEY_TOKEN = "token";
@Value("${system.config.authFilter.authUrl}")
private String authUrl;
@Value("${system.config.authFilter.tokenKey}")
private String tokenKey = RESPONSE_KEY_TOKEN;
@Autowired
private AuthApi authApi;
@Override
public boolean shouldFilter() {
RequestContext context = getCurrentContext();
return StringUtils.equals(context.getRequest().getRequestURI().toString(), authUrl);
}
@Override
public Object run() {
try {
RequestContext context = getCurrentContext();
InputStream stream = context.getResponseDataStream();
String body = StreamUtils.copyToString(stream, Charset.forName("UTF-8"));
if (StringUtils.isNotBlank(body)) {
Gson gson = new Gson();
@SuppressWarnings("unchecked")
Map<String, String> result = gson.fromJson(body, Map.class);
if (StringUtils.isNotBlank(result.get(tokenKey))) {
AuthModel authResult = authApi.encodeToken(result.get(tokenKey));
if (authResult.getStatus() != HttpServletResponse.SC_OK) {
throw new IllegalArgumentException(authResult.getErrMsg());
}
String accessToken = authResult.getToken();
result.put(tokenKey, accessToken);
}
body = gson.toJson(result);
}
context.setResponseBody(body);
} catch (IOException e) {
rethrowRuntimeException(e);
}
return null;
}
@Override
public String filterType() {
return FilterConstants.POST_TYPE;
}
@Override
public int filterOrder() {
return FilterConstants.SEND_RESPONSE_FILTER_ORDER - 2;
}
}
配置檔案,中添加授權url和傳回token的key:
system.config.authFilter.authUrl=/user/login
system.config.authFilter.tokenKey=token
context.setResponseBody(body)
這段代碼是核心,通過此方法修改傳回資料。
當使用者登入成功後,根據傳回的token,通過授權服務進行token加密,這裡加密方式使用的是JWT。防止使用者篡改資訊,非法的請求直接可以攔截在網關層。
關于Zuul過濾器的執行過程,這裡不需要多說明,源碼一看便知,ZuulServletFilter:
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
try {
init((HttpServletRequest) servletRequest, (HttpServletResponse) servletResponse);
try {
preRouting();
} catch (ZuulException e) {
error(e);
postRouting();
return;
}
// Only forward onto to the chain if a zuul response is not being sent
if (!RequestContext.getCurrentContext().sendZuulResponse()) {
filterChain.doFilter(servletRequest, servletResponse);
return;
}
try {
routing();
} catch (ZuulException e) {
error(e);
postRouting();
return;
}
try {
postRouting();
} catch (ZuulException e) {
error(e);
return;
}
} catch (Throwable e) {
error(new ZuulException(e, 500, "UNCAUGHT_EXCEPTION_FROM_FILTER_" + e.getClass().getName()));
} finally {
RequestContext.getCurrentContext().unset();
}
}
方法說明:
preRoute:執行pre類型的過濾器
postRoute:執行post類型的過濾器
route:執行route類型的過濾器
error:執行error類型的過濾器
通過context.setSendZuulResponse(false)可以終止請求的轉發,但是隻在pre類型的過濾器中設定才可以。
java B2B2C 源碼 多級分銷springmvc mybatis多租戶電子商城系統