本文介绍Zuul路由的源码以及实现动态路由的几种方式,可以先阅读Zuul1.x核心源码解析了解路由源码流程
本文基于spring-cloud-starter-zuul(SpringCloud版本为Edgware.SR3)
1、源码解析
1)、路由转发
route类型的SimpleHostRoutingFilter、RibbonRoutingFilter负责实际的请求,核心代码如下:
public class SimpleHostRoutingFilter extends ZuulFilter {
@Override
public boolean shouldFilter() {
return RequestContext.getCurrentContext().getRouteHost() != null
&& RequestContext.getCurrentContext().sendZuulResponse();
}
@Override
public Object run() {
RequestContext context = RequestContext.getCurrentContext();
HttpServletRequest request = context.getRequest();
MultiValueMap<String, String> headers = this.helper
.buildZuulRequestHeaders(request);
MultiValueMap<String, String> params = this.helper
.buildZuulRequestQueryParams(request);
String verb = getVerb(request);
InputStream requestEntity = getRequestBody(request);
if (request.getContentLength() < 0) {
context.setChunkedRequestBody();
}
String uri = this.helper.buildZuulRequestURI(request);
this.helper.addIgnoredHeaders();
try {
CloseableHttpResponse response = forward(this.httpClient, verb, uri, request,
headers, params, requestEntity);
setResponse(response);
}
catch (Exception ex) {
throw new ZuulRuntimeException(ex);
}
return null;
}
public class RibbonRoutingFilter extends ZuulFilter {
@Override
public boolean shouldFilter() {
RequestContext ctx = RequestContext.getCurrentContext();
return (ctx.getRouteHost() == null && ctx.get(SERVICE_ID_KEY) != null
&& ctx.sendZuulResponse());
}
@Override
public Object run() {
RequestContext context = RequestContext.getCurrentContext();
this.helper.addIgnoredHeaders();
try {
RibbonCommandContext commandContext = buildCommandContext(context);
ClientHttpResponse response = forward(commandContext);
setResponse(response);
return response;
}
catch (ZuulException ex) {
throw new ZuulRuntimeException(ex);
}
catch (Exception ex) {
throw new ZuulRuntimeException(ex);
}
}
两个Filter都需要满足sendZuulResponse(),即需要将Response反馈给客户端
不同点在于SimpleHostRoutingFilter需要RouteHost不为空,通过HttpClient来转发请求;RibbonRoutingFilter需要serviceId不为空而且RouteHost为空,通过Ribbon、Hystrix完成客户端负载均衡
配置示例如下:
#单实例配置 SimpleHostRoutingFilter
zuul.routes.service1.path=/service1/**
zuul.routes.service1.url=http://localhost:8081/
对符合/service1/**规则的请求路由转发到http://localhost:8081地址的路由规则,该路由规则由SimpleHostRoutingFilter实现路由转发
#多实例配置 RibbonRoutingFilter
zuul.routes.service2.path=/service2/**
zuul.routes.service2.service-id=service2
service2.ribbon.listOfServers=http://localhost:8082/,http://localhost:8083/
对符合/service2/**规则的请求路由转发到http://localhost:8082和http://localhost:8083两个实例地址的路由规则,该路由规则由RibbonRoutingFilter实现路由转发
2)、预处理
pre类型ZuulFilter中,PreDecorationFilter会根据路由信息进行预处理,其处理结果决定了使用哪个route类型ZuulFilter来实际处理请求
public class PreDecorationFilter extends ZuulFilter {
@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
final String requestURI = this.urlPathHelper.getPathWithinApplication(ctx.getRequest());
//根据requestURI获取路由信息
Route route = this.routeLocator.getMatchingRoute(requestURI);
//路由信息存在
if (route != null) {
String location = route.getLocation();
if (location != null) {
ctx.put(REQUEST_URI_KEY, route.getPath());
ctx.put(PROXY_KEY, route.getId());
if (!route.isCustomSensitiveHeaders()) {
this.proxyRequestHelper
.addIgnoredHeaders(this.properties.getSensitiveHeaders().toArray(new String[0]));
}
else {
this.proxyRequestHelper.addIgnoredHeaders(route.getSensitiveHeaders().toArray(new String[0]));
}
if (route.getRetryable() != null) {
ctx.put(RETRYABLE_KE

本文详细解读了Zuul 1.x路由转发机制,涉及SimpleHostRoutingFilter与RibbonRoutingFilter的区别,以及PreDecorationFilter如何根据路由进行预处理。还介绍了动态路由的实现,包括刷新路由策略和自定义路由配置的示例。
最低0.47元/天 解锁文章
168万+

被折叠的 条评论
为什么被折叠?



