基于 lor.index 的错误处理机制设计

栏目: Lua · 发布时间: 5年前

内容简介:目前主流 openersty的开发都采用了 lor 这个框架,本文根据本拐的一些经验,总结了一些实践经验在 Lua的标准库中,有一个函数,用于程序向外界抛出异常,即 error ,其官方文档如下:

摘要

目前主流 openersty的开发都采用了 lor 这个框架,本文根据本拐的一些经验,总结了一些实践经验

Lua 的错误处理机制

error

Lua 的标准库中,有一个函数,用于程序向外界抛出异常,即 error ,其官方文档如下:

error (message [, level])

Terminates the last protected function called and returns message as the error message. Function error never returns. Usually, error adds some information about the error position at the beginning of the message. The level argument specifies how to get the error position. With level 1 (the default), the error position is where the error function was called. Level 2 points the error to where the function that called error was called; and so on. Passing a level 0 avoids the addition of error position information to the message.

即:

终结当前的函数调用,并返回错误信息。

其中第二个参数为 level ,当为1 时,抛出的错误为error的调用位置,为2时为调用 error 的函数位置。

示例代码如下:

1.  local function test_error()
2.      error('the error throw',1)
3.  end
4.  test_error()

当运行这个脚本时,提示如下:

lua: err_show.lua:2: the error is throw
    stack traceback:
    [C]: in function 'error'
    err_show.lua:2: in function 'test_error'
    err_show.lua:4: in main chunk
    [C]: ?

如果改为:

1.  local function test_error()
2.      error('the error throw',2)
3.  end4.  test_error()

则提示变为:

lua: err_show.lua:4: the error is throw
    stack traceback:
	[C]: in function 'error'
	err_show.lua:2: in function 'test_error'
	err_show.lua:4: in main chunk
	[C]: ?

pcall 与 xpcall

如果在代码中,直接调用 error,那么脚本就直接挂掉了,显然不是我们想要的,当然,lua 本身也这么想 :) ,为了处理程序中的错误,lua 提供了 pcall 和 xpcall,两个函数,其官方文档如下:

pcall (f, arg1, ···)

Calls function f with the given arguments in protected mode. This means that any error inside f is not propagated; instead, pcall catches the error and returns a status code. Its first result is the status code (a boolean), which is true if the call succeeds without errors. In such case, pcall also returns all results from the call, after this first result. In case of any error, pcall returns false plus the error message.

即,pcall 会以安全模式调用 f(arg1,...),当f正确执行时,pcall 会返回 true, fresult 否则会返回 false ,err

这样,我们的函数变成了:

1 local function test_error(success)
  2         if success == true then
  3                 return true,"the function is runned"
  4         else
  5                 error('the error is throw ',2)  6         end
  7 end
  8
  9 local call_result,func_result,msg  = pcall(test_error,true) 
 10 if call_result == true then
 11         print(func_result) 
 12         print(msg) 
 13 else
 14         print(func_result) 
 15 end

运行这个脚本,返回的是:

truethe function is runned

如果我们将第9行的 true 改成 false ,再运行,则结果为:

the error is throw

pcall 要靠返回值来进行错误处理的二次判断,对于有结癖的程序员,反复的 if - else 显然是大家不能接收的,于是 lua 又提供了与 pcall 类似的 xpcall

xpcall (5.1)

xpcall (f, err) This function is similar to pcall, except that you can set a new error handler.

xpcall calls function f in protected mode, using err as the error handler. Any error inside f is not propagated; instead, xpcall catches the error, calls the err function with the original error object, and returns a status code. Its first result is the status code (a boolean), which is true if the call succeeds without errors. In this case, xpcall also returns all results from the call, after this first result. In case of any error, xpcall returns false plus the result from err.

xpcall (f, msgh [, arg1, ···]) (5.3)

This function is similar to pcall, except that it sets a new message handler msgh.

即,xpcall 允许传入一个错误处理函数,当 xpcall调用出错时,会调用 err函数 ,为了测试,代码如下:

1 local function test_error(success)
  2         if success == true then
  3                 return true,"the function is runned"
  4         else
  5                 error('the error is throw ',2)  6         
            end
  7 end
  8 local function err_handle (err)
  9         print('the error happened:'.. err ) 10 end
 11 local call_result,func_result,msg = xpcall(test_error,err_handle,true) 12 if call_result then
 13         print (msg) 14 end
 15 call_result,func_result,msg = xpcall(test_error,err_handle,false) 16 print (call_result)

这段代码的运行结果如下:

the function is runned
the error happened:the error is throw false

值得注意的是,xpcall 只有在lua 5.2,5.3 的版本可以传调用 f的参数 ,在 5.1.X 是不支持的。

Lor的错误处理机制及工程应用

lor的错误处理

在 lor 的官方文档中,错误处理的机制为提供了一个 erroruse 的路由机制,说明如下:

app:erroruse用于加载一个错误处理插件(middleware)

参数说明

  • path, 插件作用的路径,可以为空,也就是说app:erroruse可以只有一个middleware参数,这时插件作用在所有path上

  • middleware,插件,格式为function(err, req, res, next) end, 注意与use api不同的是这个function有4个参数.

示例

该实例加载了一个作用在所有路径上的插件,也就是说只要有地方发生了错误,并且没有显式地调用response对象的输出方法,则会路由到这个错误插件进行处理。

-- 统一错误处理插件
app:erroruse(function(err, req, res, next)
-- err是错误对象,直接将err打到response,生产环境请勿这样做
        res:status(500):send(err)    
end)

原理

lor 对错误处理的代码片段如下:

local ok, ee = xpcall(function()
    error_handler.func(err, req, res, next)end, function(msg)
    if msg then
        if type(msg) == "string" then
            err_msg = msg        
        elseif type(msg) == "table" then
            err_msg = "[ERROR]" .. table_concat(msg, "|") .. "[/ERROR]"
        end
    else
        err_msg = ""
    end
    err_msg = string_format("%s\n[ERROR in ErrorMiddleware#%s(%s)] %s \n%s", err, idx, error_handl    er.id, err_msg, traceback())
    ned)    
    if not ok then 
        return done(err_msg)    
    end 
    --......
    next(err_msg)
    --other code

可以看出

  1. lor路由调用以 xpcall 进行调用

  2. 当路由调用出错时,也就时当有 error 函数执行时,会将 error 的信息拼成 string 然后交给错误处理中间件执行,也就是说,我们如果只用 lor 现成的错误处理,那么只能得到 string的返回信息,并且这种返回包含了栈的调试信息, 然而在大部分工程化的应用中,我们或许早已经习惯了以 error-code,error-message 这种形式进行错误的处理。 3

工程化的错误处理方式

由上面的讨论,我们们需求很明确 :

  1. 可以以 k-v 的形式进行错误的处理

  2. 可以在程序中很容易的抛出错误,而不用进行层层判断。

基于这种,我们使用 ngx.var 进行保存错误过程码,然后在全局错误处理中间件中集中处理,即,定义 error_helper 如下:

local M = {}
M.error_code = {
    ERROR_CODE1=1,
    ERROR_CODE2=2,
    ERROR_CODE3=3
}
local error_msg = {}
error_msg [M.error_code.ERROR_CODE1] = "错误1"
error_msg [M.error_code.ERROR_CODE2] = "错误2"
error_msg [M.error_code.ERROR_CODE3] = "错误3"
M:throw = funcction (err)
    ngx.var.error_code = err
    error(err)
end
M:get_msg = function()    local err = ngx.var.error_code
    ngv.var.error_code = nil    return { code = err,msg = error_msg[err] not "未知错误" }
endreturn M

那么在这种情况下,我们的代码变成了

local error_helper = require("error_helper")
local throw = error_helper.throw
local error_code = error_helper.error_code
---other code .... 

-- 错误处理时

if (err) then
    throw (error_code.ERR_CODE1)
end

之后,在全局引用错误处理中间件

app:erroruse(function(err, req, res, next)
        res:json(error_helper:get_msg()
)end

即可以达到一种比较优雅,易于维护的错误处理方式


以上所述就是小编给大家介绍的《基于 lor.index 的错误处理机制设计》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

宇宙涟漪中的孩子

宇宙涟漪中的孩子

谢云宁 / 四川科学技术出版社 / 2017-11 / 28.00元

近未来。日冕科技公司通过建造围绕太阳的光幕搜集了近乎无穷的能源,这些能源主要用于地球上的网络空间建设。随着全球网络时间频率的不断提升,越来越多的人选择接驳进虚拟空间,体验现实中难以经历的丰富人生。 网络互动小说作者宁天穹一直自认为是这些人中普通的一员,有一天却被一名读者带进反抗组织,了解到日冕公司的各种秘密,并被告知自己的小说将在抵抗运动中起到重要作用。 起初他拒绝参与,但看到地球被笼......一起来看看 《宇宙涟漪中的孩子》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具