Zuul路由转发源码解析及动态路由实现

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

本文介绍Zuul路由的源码以及实现动态路由的几种方式,可以先阅读Zuul1.x核心源码解析了解路由源码流程

本文基于spring-cloud-starter-zuul(SpringCloud版本为Edgware.SR3)

1、源码解析

1)、路由转发

route类型的SimpleHostRoutingFilterRibbonRoutingFilter负责实际的请求,核心代码如下:

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
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

邋遢的流浪剑客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值