源起
QQ群经常看到有同学问(Vanilla/OpenResty开发:205773855,OpenResty技术交流2群:481213820):
- 如何让Vanilla支持Restful(或者Vanilla如何支持xxxx样子的URL访问)?
- Vanilla的路由器如何使用?
- Vanilla的请求路由是如何实现的?
综上问题都是一个事儿:如何给Vanilla(OpenResty)添加一个路由协议?
本文将以一个小例子入手,展示在Vanilla中如何自定义一个路由协议,基于此帮助大家理解Vanilla中路由器、路由协议的用法和实现,当然如果你对实现自己的路由协议不感冒的话,vanilla-0.1.0.rc4
已经实现了两种比较实用的路由协议vanilla.v.routes.restful
和vanilla.v.routes.simple
能满足当前各种URI路由需求,可直接使用,用法见相关文档地址:https://idevz.gitbooks.io/vanilla-zh/content/route.html。这里给出一个vanilla.v.routes.restful
路由的配置实例:
local restful = {
v1={},
v={}
}
restful.v.GET = {
{pattern = '/uid/:user_id/uname/:name', controller = 'test.index', action = 'web_rule'},
{pattern = '/', controller = 'test.index', action = 'web_root'},
}
restful.v1.GET = {
{pattern = '/uid/:user_id/uname/:name', controller = 'test.index', action = 'api_v1_rule'},
{pattern = '/', controller = 'test.index', action = 'api_root'},
{pattern = '/test/index/index', controller = 'test.index', action = 'index'},
}
return restful
Vanilla项目地址:
Github:https://github.com/idevz/vanilla
GitOSC:http://git.oschina.net/idevz/vanilla
如果vanilla.v.routes.restful
和vanilla.v.routes.simple
不能满足你的需求,你想在自己的项目中DIY自己的路由协议,请继续往下:
如何给Vanilla(OpenResty)添加一个路由协议?
先看例子,再学原理(例子:给APP添加一个跟功能与simple_route一样的路由协议routes.idevz
)
实现步骤
- 在项目中添加
application/library/routes/idevz.lua
- 定义一个表,包含
route_name
属性,并实现__tostring
元方法(路由器基于此管理路由协议栈) - 在
idevz.lua
中实现match
方法(功能:根据当前请求URI返回对应的controller
和action
)
关键两点
-
route_name
属性,并实现__tostring
元方法 -
match
方法
相关代码实现如下:
-- perf
local error = error
local ngxmatch=ngx.re.gmatch
-- init iDevz and set routes
local iDevz = {}
function iDevz:new(request)
local instance = {
route_name = 'routes.idevz',
request = request
}
setmetatable(instance, {
__index = self,
__tostring = function(self) return self.route_name end
})
return instance
end
function iDevz:match()
local uri = self.request.uri
if uri == '/' then
return 'index', 'index'
end
--在此实现URI路由逻辑,并返回contrllor_name, action_name
return contrllor_name, action_name
end
return iDevz
原理
Vanilla运行在OpenResty的content Phase
,由content_by_lua_file
驱动,当用户请求过来时会初始化当前APP请求实例,并做相关配置解析、视图引擎配置、插件装载、路由设置等初始化工作,紧接着就是请求路由分发、处理... 也就是run
的指令一下就开始进入请求路由。
Vanilla实现了一个路由器vanilla.v.router
(注意这里是router
,是er
路由器,区别于后面的路由协议route
)和由这个路由协器管理的一个路由协议栈(self.routes
),这个栈管理着一序列路由协议,默认使用vanilla.v.routes.simple
,Vanilla通过遍历这个路由协议栈里面各个route
的match
方法来完成请求的路由。这个match
方法只做一件事“根据当前请求的URI告诉每个请求该去哪个controller
和哪个action
”。
下面是router
目前提供的相关方法:
function Router:new(request) --传入request实例初始化路由器,默认已经启用:vanilla.v.routes.simple
function Router:addRoute(route, only_one) --添加路由协议
function Router:removeRoute(route_name) --传入路由协议名称删除路由协议
function Router:getRoutes() --获取当前的路由协议栈
function Router:getCurrentRoute() --获取当前请求所使用的路由协议实例
function Router:getCurrentRouteName() --获取当前请求所使用的路由协议名称
function Router:route() --路由当前请求
** 所以给Vanilla(OpenResty)添加一个路由协议的关键就在于实现这个match
方法欢迎大家各自按需DIY **
在bootstrap中使用实例
function Bootstrap:initRoute()
local router = self.dispatcher:getRouter()
local simple_route = require('vanilla.v.routes.simple'):new(self.dispatcher:getRequest())
local restful_route = require('vanilla.v.routes.restful'):new(self.dispatcher:getRequest())
local idevz_route = require('routes.idevz'):new(self.dispatcher:getRequest())
router:addRoute(restful_route, true)
router:addRoute(idevz_route, true)
router:addRoute(simple_route)
router:removeRoute('vanilla.v.routes.restful')
router:removeRoute('vanilla.v.routes.simple')
-- print_r(router:getRoutes())
end
感谢
Vanilla开源以来的很长一段时间里一直只支持一种单一的简单路由协议simple_route,这让很多朋友意犹未尽,甚至批评Vanilla不是框架,而是骨架:),首先感谢各位群友、Vanilla用户...感谢大家对Vanilla的支持与关注,我想象中的Vanilla是一个保持很好的扩展性、易用性,让OpenResty开发更简单方便,性能强劲的同时又不失优雅小巧的OpenResty开发框架,虽然现在的vanilla-0.1.0.rc4
离这个目标还有一段距离,但至少方向是这样的。Vanilla是已知的第一款国产OpenResty MVC Web框架,所以它离你更近:)。感谢持续关注,我们在努力完善中。