如何給Vanilla(OpenResty)添加一個路由協議

###源起 QQ羣常常看到有同窗問(Vanilla/OpenResty開發:205773855,OpenResty技術交流2羣:481213820):html

  • 如何讓Vanilla支持Restful(或者Vanilla如何支持xxxx樣子的URL訪問)?
  • Vanilla的路由器如何使用?
  • Vanilla的請求路由是如何實現的?

綜上問題都是一個事兒:如何給Vanilla(OpenResty)添加一個路由協議?git

本文將以一個小例子入手,展現在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路由的配置實例:github

local restful = {
    v1={},
    v={}
}

restful.v.GET = {
    {pattern = '/user/:user_id', controller = 'test.index', action = 'web_rule'},
    {pattern = '/', controller = 'test.index', action = 'web_root'},
}
restful.v1.GET = {
    {pattern = '/user/:user_id', 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項目地址:web

Github:https://github.com/idevz/vanillabootstrap

GitOSC:http://git.oschina.net/idevz/vanillaapi

若是vanilla.v.routes.restfulvanilla.v.routes.simple(默認爲simple若是須要使用restful路由協議,則須要在bootstrap中打開Bootstrap:initRoute())不能知足你的需求,你想在本身的項目中DIY本身的路由協議,請繼續往下:restful

###如何給Vanilla(OpenResty)添加一個路由協議?app

先看例子,再學原理(例子:給APP添加一個跟功能與simple_route同樣的路由協議routes.idevz框架

####實現步驟ide

  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」。

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框架,因此它離你更近:)。感謝持續關注,咱們在努力完善中。

相關文章
相關標籤/搜索