前面几篇讲了微服务的诸多介绍以及一些开源的网关,开源虽好,但有时跟团队用的技术栈和平台不一样,而且有些开源的网关功能太多,学习成本太高,远远高于自研的成本,因为有时,我们仅仅需要网关某几个的功能,比如路由转发、接口鉴权等等。今天,小编就来结合Asp.Net mvc webapi技术分享下微服务网关中路由转发功能的实现。
首先来张网关的总体架构或说是设计图:
nginx+asp.net webapi+redis+sqlserver+mongodb
nginx作为反向代理服务器,将比如http://www.xxx.com/apigateway/后面的地址统一转发给api网关站点。
然后到了api网关这里,由于api网关用的是webapi,在这个站点后面的路由就是asp.net webapi的路由机制了(还是利用asp.net mvc的路由机制,在用当下webapi技术来套一层皮吐出restful风格的api接口)。
那大家会问,那这么多接口,难道来一个接口就要修改下路由配置文件然后在发布吗?
答案肯定不是这样的。从上图中,有个MSSQL,这个就是我们把mvc中的路由映射关系持久化存储在MSSQL数据库中,但是每次请求都去关系型数据库MSSQL查接口,性能也是不理想,所以,我们可以把接口缓存到像Redis这种内存数据库中。然后请求的跟踪日志存储在MongoDB中,方便网关集群分布式部署时,好查日志。
当时,原理是这样,这里比较关键的一点是,那么nginx到底该转发到webapi中的哪个接口呢?
我们是这样设计的,所有经过nginx的请求(当时路径前缀是http://www.xxx.com/apigateway/)统一转发到webapi中ApigatewayController/Reroute方法中,关键是这部该如何实现了。这里用到两个过滤器:
public class NotFoundControllerSelector : DefaultHttpControllerSelector
{
public NotFoundControllerSelector(HttpConfiguration configuration)
: base(configuration)
{
}
public override HttpControllerDescriptor SelectController(HttpRequestMessage request)
{
HttpControllerDescriptor decriptor = null;
try
{
decriptor = base.SelectController(request);
}
catch (HttpResponseException ex)
{
var code = ex.Response.StatusCode;
if (code != HttpStatusCode.NotFound)
throw;
var routeValues = request.GetRouteData().Values;
routeValues["controller"] = "ApiGateway";
routeValues["action"] = "ReRoute";
decriptor = base.SelectController(request);
}
return decriptor;
}
}
public class NotFoundActionSelector : ApiControllerActionSelector
{
public NotFoundActionSelector()
{
}
public override HttpActionDescriptor SelectAction(HttpControllerContext controllerContext)
{
HttpActionDescriptor decriptor = null;
try
{
decriptor = base.SelectAction(controllerContext);
}
catch (HttpResponseException ex)
{
var code = ex.Response.StatusCode;
if (code != HttpStatusCode.NotFound && code != HttpStatusCode.MethodNotAllowed)
throw;
var routeData = controllerContext.RouteData;
routeData.Values["action"] = "ReRoute";
IHttpController httpController = new CoreController();
controllerContext.Controller = httpController;
controllerContext.ControllerDescriptor = new HttpControllerDescriptor(controllerContext.Configuration, "ApiGatway", httpController.GetType());
decriptor = base.SelectAction(controllerContext);
}
return decriptor;
}
}
经过上面两个过滤器,就会将http://www.xxx.com/apigateway/api/后面的所有请求转发到http://www.xxx.com/apigateway/api/apigatway/reroute/
在reroute这个action你就可以实现网关的所有功能了,比如查Redis(MSSQL)、找到对应接口。。。
当然,做得优雅一点,可以用流水线的方式:
当然,这只是C#语言实现的一部分,你也可以用java或Go或Node.js去实现,思想都是一样的,技术实现不同而已。
如果觉得有用,大家可以关注我,也可以下方留言互动一起探讨。
閱讀更多 墨漂碼農 的文章