🔬
OpenResty 最佳实践
  • 序
  • 入门篇
  • Lua 入门
    • Lua 简介
    • Lua 环境搭建
    • Lua 编辑器选择
    • 基础数据类型
    • 表达式
    • 控制结构
      • if/else
      • while
      • repeat
      • for
      • break,return 和 goto
    • Lua 函数
      • 函数的定义
      • 函数的参数
      • 函数返回值
      • 全动态函数调用
    • 模块
    • String 库
    • Table 库
    • 日期时间函数
    • 数学库函数
    • 文件操作
  • Lua 高阶
    • 元表
    • 面向对象编程
    • 局部变量
    • 判断数组大小
    • 非空判断
    • 正则表达式
    • 虚变量
    • 抵制使用 module() 定义模块
    • 调用代码前先定义函数
    • 点号与冒号操作符的区别
    • module 是邪恶的
    • FFI
    • 什么是 JIT
  • Nginx
    • Nginx 新手起步
    • location 匹配规则
    • 静态文件服务
    • 日志
    • 反向代理
    • 负载均衡
    • 陷阱和常见错误
  • OpenResty
    • 环境搭建
      • Windows 平台
      • CentOS 平台
      • Ubuntu 平台
      • Mac OS X 平台
    • Hello World
    • 与其他 location 配合
    • 获取 uri 参数
    • 获取请求 body
    • 输出响应体
    • 日志输出
    • 简单 API Server 框架
    • 使用 Nginx 内置绑定变量
    • 子查询
    • 不同阶段共享变量
    • 防止 SQL 注入
    • 如何发起新 HTTP 请求
    • 如何完成 bit 操作
      • 一,复习二进制补码
      • 二,复习位运算
      • 三,LuaJIT 和 Lua BitOp Api
      • 四,位运算算法实例
      • 五,Lua BitOp 的安装
  • LuaRestyRedisLibrary
    • 访问有授权验证的 Redis
    • select+set_keepalive 组合操作引起的数据读写错误
    • redis 接口的二次封装(简化建连、拆连等细节)
    • redis 接口的二次封装(发布订阅)
    • pipeline 压缩请求数量
    • script 压缩复杂请求
    • 动态生成的 lua-resty-redis 模块方法
  • LuaCjsonLibrary
    • json 解析的异常捕获
    • 稀疏数组
    • 空 table 编码为 array 还是 object
  • PostgresNginxModule
    • 调用方式简介
    • 不支持事务
    • 超时
    • 健康监测
    • SQL 注入
  • LuaNginxModule
    • 执行阶段概念
    • 正确的记录日志
    • 热装载代码
    • 阻塞操作
    • 缓存
    • sleep
    • 定时任务
    • 禁止某些终端访问
    • 请求返回后继续执行
    • 调试
    • 请求中断后的处理
    • 我的 lua 代码需要调优么
    • 变量的共享范围
    • 动态限速
    • shared.dict 非队列性质
    • 正确使用长链接
    • 如何引用第三方 resty 库
    • 典型应用场景
    • 怎样理解 cosocket
    • 如何安全启动唯一实例的 timer
    • 如何正确的解析域名
  • LuaRestyDNSLibrary
    • 使用动态 DNS 来完成 HTTP 请求
  • LuaRestyLock
    • 缓存失效风暴
  • OpenResty 与 SSL
    • HTTPS 时代
    • 动态加载证书和 OCSP stapling
    • TLS session resumption
  • 测试
    • 代码静态分析
    • 单元测试
    • 代码覆盖率
    • API 测试
    • 性能测试
    • 持续集成
    • 灰度发布
      • 分流引擎设计
      • 控制台开发
      • 向运维平台发展
  • Web 服务
    • API 的设计
    • 数据合法性检测
    • 协议无痛升级
    • 代码规范
    • 连接池
    • C10K 编程
    • TIME_WAIT 问题
    • 与 Docker 使用的网络瓶颈
  • 火焰图
    • 什么是火焰图
    • 什么时候使用
    • 如何安装火焰图生成工具
    • 如何定位问题
    • 拓展阅读
    • FAQ
Powered by GitBook
On this page
  • pcall 函数
  • cjson.safe 模块接口
Edit on GitHub
  1. LuaCjsonLibrary

json 解析的异常捕获

首先来看最最普通的一个 json 解析的例子(被解析的 json 字符串是错误的,缺少一个双引号):

-- http://www.kyne.com.au/~mark/software/lua-cjson.php
-- version: 2.1 devel

local json = require("cjson")
local str  = [[ {"key:"value"} ]]  -- json 串中缺少一个双引号

local t    = json.decode(str)
ngx.say(" --> ", type(t))


-- ... do the other things
ngx.say("all fine")

代码执行错误日志如下:

2015/06/27 00:01:42 [error] 2714#0: *25 lua entry thread aborted: runtime error: ...ork/git/github.com/lua-resty-memcached-server/t/test.lua:8: Expected colon but found invalid token at character 9
stack traceback:
coroutine 0:
    [C]: in function 'decode'
    ...ork/git/github.com/lua-resty-memcached-server/t/test.lua:8: in function <...ork/git/github.com/lua-resty-memcached-server/t/test.lua:1>, client: 127.0.0.1, server: localhost, request: "GET /test HTTP/1.1", host: "127.0.0.1:8001"

这可不是期望结果:decode 失败,500 错误直接退了。改良了一下代码:

local decode = require("cjson").decode

function json_decode( str )
    local ok, t = pcall(decode, str)
    if not ok then
        return nil
    end

    return t
end

pcall 函数

如果需要在 Lua 中处理错误,必须使用函数 pcall(protected call)来包装需要执行的代码。

pcall 接收一个函数和要传递给那个函数的参数,并执行。

语法格式如下:

local status, res = pcall(function_name, params)
if status then
    -- 没有错误
    -- 返回 res
else
    -- 有一些错误
    -- 处理错误的代码
end

接收的参数 (两个):

  • 第一个参数:被调用的函数,(可以是函数名或完整的函数体);

  • 第二个参数:传给被调用函数的参数。

执行结果 (两种情况):

  • 有错误;

  • 无错误。

返回值 (两个):

  • 第一个是 pcall 函数的运行状态:true 或者 false;

  • 第二个是被调用函数的返回值: 正常执行结果或者报错信息 (errorinfo)。

示例

  • 1、 没有错误的情况,test_pcall_good.lua

    local function foo(str)
        print("test pcall" .. str)
        return str
    end
    
    local str = 'hello'
    status, res = pcall(foo, str)
    
    print(status)
    print(res)

    执行结果:

    -- output:
    test pcall: hello
    true
    hello
  • 2、 发生错误的情况,test_pcall_bad.lua

    local function bar(str)
        print("test pcall" .. st)  -- 这里传入的变量名写错了
        return str
    end
    
    local str = 'hello'
    status, res = pcall(bar, str)
    
    print(status)
    print(res)

    执行结果:

    -- output:
    false
    test_pcall_bad.lua:2: attempt to concatenate global 'st' (a nil value)

pcall 以一种 “保护模式” 来调用第一个参数,因此 pcall 可以捕获函数执行中的任何错误。 通常在错误发生时,总希望可以得到更多的调试信息,而不只是发生错误的位置。但 pcall返回时,它已经销毁了调用栈的部分内容。

Lua 还提供了 xpcall 函数,xpcall 接收的第二个参数——一个错误处理函数,当错误发生时,Lua 会在调用栈展开(unwind)之前调用错误处理函数,于是就可以在这个函数中使用debug 库来获取关于错误的额外信息了。 有兴趣的同学,请更多了解下 Lua 中的异常处理。

cjson.safe 模块接口

另外,可以使用 CJSON 2.1.0,该版本新增一个 cjson.safe 模块接口,该接口兼容 cjson 模块,并且在解析错误时不抛出异常,而是返回 nil。

local json = require("cjson.safe")
local str  = [[ {"key:"value"} ]]  -- json 串中缺少一个双引号

local t    = json.decode(str)
if t then
    ngx.say(" --> ", type(t))
end
PreviousLuaCjsonLibraryNext稀疏数组

Last updated 2 years ago