我为什么要再给lua写一个json模块

  最近要给自己编写的服务器加上json解析模块。根据我当前的项目,可以预测服务器中使用json的地方:

  • 通信。由于与客户端通信使用google protocolbuffer,仅在与SDK通信中使用json
  • 配置。我们当前直接将配置转换为lua table。但其他项目依然有很大概率要使用json作为配置。
  • MongoDB。项目中使用MongoDB作为数据存储,很多接口需要用到json.

而在我的服务器中,写了一个MongoDB lua driver,可以直接将lua table转换为MongoDB的bson数据结构,DB这块不需要json了。像配置都是静态数据,一次加载后不会再加载了。而SDK通信也仅限于登录充值,相对来说对json的效率要求不是很高。

  由于服务器底层以C++为主,上层为lua,当然是先查找lua的json模块。在http://lua-users.org/wiki/JsonModules上,列出了主流的lua json模块。但是常用的也就lua4json和mp-cjson两个。lua4json是我们现在使用的,每一个玩家存库,都要将lua table转为json再传给MongoDB接口。从目前来看,性能还是可以的,而且是纯lua。mp-cjson貌似是cocos2dx标配的json解析模块,底层是基于cjson的,效率高,用的人也多。

  对于lua而言,传统的数组和关联数据都是lua table,要转为json时就要做一些判断才能知道是array还是object。我希望是这样的:

  • 如果key都是int,则是数组。而如果key不是从1开始,则是稀疏数组(sparse array)。
  • 允许通过元表指定是array还是object。如果指定为object,则所有key会被转换为string。如果指定为array而key中包含float、string则使用自增的int做key。

  lua4json是不能指定是array还是object的,并且尝试将key为float等也转换为array。因此一个空的lua table( {} )只能由lua4json的作者定死为array。这对于从lua写进数据库,从lua读出来也不是太大的问题。但在实际使用中发现,如果你尝试在Mongo Shell中做些操作或者用java写的后台读取数据时,就有点麻烦了。不过json4lua是纯lua的,我改改就可以用了。在最后进行测试时,解析从https://github.com/miloyip/nativejson-benchmark中下载的一个2M多的json串,花了7分多钟。结果,我放弃了,万一哪天策划给我来个8M的配置表,我开个服务器岂不得用半个钟。

  mp-cjson我看了一下api(http://www.kyne.com.au/~mark/software/lua-cjson-manual.html),有一个encode_sparse_array函数可以处理sparse array,但也没有可以强制指定array、object的函数。

  在泛型语言与强类型语言交互的时候,确定类型很重要。比如我有这样一个lua table:

local reply = 
{
    array_item = {},
    map_id     = {}
}

现在我要将他转换为json存到MongoDB或者发送到java后台,json串应该是

{ "array_item":[],"map_id":{} }

上面的两个库,没有一个做得到。于是我决定自己写一个lua的json模块。

  自己再写基础的json解析是不太可能的了。我决定使用小巧的parson,然后给他加上lua的粘合层,就可以成为lua的模块了,命名为lua_parson。我定了比较详细的规则:

  • 如果key值都为int并且小于INT_MAX,必定为数组。
  • 如果在元表指定__array并且值为true,则必定为数组
  • 如果是数组并且key都为int,则为sparse array,空位直接使用null填充
  • 如果1、2两点不成立,则必为object。object中所有不为string的key都将直接转换为string

  现在这个库放在https://github.com/changnet/lua_parson。安装使用也比较简单。注意这个库不是线程安全的。

  我自己以前也觉得不要重复造轮子,但现在觉得别人的轮子并不是那么好用。虽然实际情况项目中,上面列出的极端情况还没出现过,那些库也可以将就者用。即使出现了,也可以换种方法解决。但如果可以完美一点,为什么不去做呢?

### 回答1: 当然可以! 下面是一个简单的例子,该插件可以将响应体中的所有字符转换为大: ```lua local json = require "cjson" local _M = {} function _M.rewrite(response) local body = response.body if body then response.body = string.upper(body) end return response end return _M ``` 这个插件使用了 cjson 库来解析和修改 json 格式的响应体。安装cjson库可以使用luarocks 安装,在命令行输入: ``` luarocks install cjson ``` 这个插件的工作流程如下: 1. 通过 `response.body` 获取响应体 2. 调用 `string.upper` 函数将响应体中所有字符转换为大 3. 使用 `response.body` 将修改后的响应体重新赋值 4. 最后返回修改后的 `response` 对象 需要注意的是,上面这个例子只能处理字符串类型的响应体,如果要处理其他类型的响应体,需要进行适当的修改。 最后需要将这个插件配置到Apisix中,在Apisix的配置文件中加入如下代码: ``` - plugin: response-body-upper config: {} ``` 完整示例可以参考Apisix文档. ### 回答2: 当然可以帮您编一个用于转换响应体的 apisix 插件。下面是一个示例: ```lua local cjson = require("cjson.safe") local _M = {} function _M.transform_response_body(conf, ctx) -- 获取响应体内容 local response_body = ngx.arg[1] -- 进行响应体的转换操作 local transformed_body = cjson.decode(response_body) -- 修改转换后的响应体 transformed_body.new_property = "new_value" -- 将修改后的响应体序列化为 JSON 字符串 local new_response_body = cjson.encode(transformed_body) -- 修改响应体的长度 ngx.arg[2] = string.len(new_response_body) -- 更新响应体内容 ngx.arg[1] = new_response_body end return _M ``` 该示例中的 `transform_response_body` 函数将会被调用来转换响应体。您可以根据您的需求自定义该函数内的转换逻辑。在示例中,我们使用 `cjson` 模块来进行 JSON 格式的序列化和反序列化操作,将响应体转换为 Lua 并进行修改,然后再序列化回 JSON 字符串以更新响应体内容。 请注意,使用以上代码仅仅可以作为您编 apisix 插件的参考示例,具体实现还需要根据您的具体需求进行调整。希望这样的回答对您有所帮助。 ### 回答3: 以下是一个使用Lua的apisix插件,用于转换响应体: ```lua local BasePlugin = require("apisix.plugins.base") local plugin_name = "response-transform" local ResponseTransformHandler = BasePlugin:extend() ResponseTransformHandler.PRIORITY = 10 function ResponseTransformHandler:new() ResponseTransformHandler.super.new(self, plugin_name) end function ResponseTransformHandler:access(conf, ctx) ResponseTransformHandler.super.access(self) -- 检查是否需要转换响应体 if conf.transform_body == true then -- 获取原始响应体 local res_body = ngx.arg[1] -- 执行转换操作,这里可以根据需要进行自定义逻辑 local transformed_body = res_body:gsub("foo", "bar") -- 保存转换后的响应体 ngx.arg[1] = transformed_body end end return ResponseTransformHandler ``` 请注意,上述代码中的转换逻辑仅仅是简单的示范,您可以根据实际需求进行自定义转换操作。 要将此插件与Apisix一起使用,您可以将该代码保存到`response_transform.lua`文件中,并将其放置在Apisix的插件目录中。然后在Apisix的配置文件中添加以下内容来启用插件: ```yaml plugins: - name: response-transform enable: true config: transform_body: true ``` 上述配置将在所有请求的响应体上执行转换操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值