如何给Vanilla(OpenResty)添加一个路由协议

源起

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.restfulvanilla.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.restfulvanilla.v.routes.simple不能满足你的需求,你想在自己的项目中DIY自己的路由协议,请继续往下:

如何给Vanilla(OpenResty)添加一个路由协议?

先看例子,再学原理(例子:给APP添加一个跟功能与simple_route一样的路由协议routes.idevz

实现步骤

  1. 在项目中添加application/library/routes/idevz.lua
  2. 定义一个表,包含route_name属性,并实现__tostring元方法(路由器基于此管理路由协议栈)
  3. idevz.lua中实现match方法(功能:根据当前请求URI返回对应的controlleraction

关键两点

  1. route_name属性,并实现__tostring元方法
  2. 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通过遍历这个路由协议栈里面各个routematch方法来完成请求的路由。这个match方法只做一件事“根据当前请求的URI告诉每个请求该去哪个controller和哪个action”。

如何给Vanilla(OpenResty)添加一个路由协议_第1张图片
router原理

下面是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框架,所以它离你更近:)。感谢持续关注,我们在努力完善中。

你可能感兴趣的:(如何给Vanilla(OpenResty)添加一个路由协议)