Nginx openresty plan

From PostgreSQL 中文维基, PostgreSQL 中文站, PostgreSQL 中国社区, PostgreSQL Chinese community

Jump to: navigation, search

本文档提供了对淘宝 SDS 的 openresty 项目的一个计划草案。

目录

[编辑] 文档版本

版本: 0.01

创建日期: 2009 年 9 月 13 日

最后一次修订: 2009 年 9 月 13 日

[编辑] 项目背景

为适应 SDS 部门的在线统计报表应用和 Hardoop/Hive 集群管理的需要,通过 OpenResty 来提供对 Oracle/mysql/hardoop/hive 等多种异质后端的 REST 层抽象,简化前端 PHP 和 AJAX 应用的开发。

基于原雅虎中国 OpenResty.pm 的 API 设计和一些理念,并吸取了其设计和实现上的许多经验和教训。

[编辑] 设计目标

[编辑] 高性能

  • 缓慢的后端查询不会阻塞单个 server worker 进程快速响应那些后端用时少的请求。
  • 在后端性能足够好的情况下,能在普通的双核机器上实现单机 2000+ QPS,并能支持 1000 并发以上。
  • 对出入的 HTTP 请求的数据尽量使用流式处理的方式,以降低单请求的大数据量对 server 的 RAM 等资源的冲击。
  • 在 C 级别上尽量减少数据块的复制和拷贝。

[编辑] 高稳定性

  • 通过 nginx 核心模块 req_limit 实现基于客户端 IP 的访问频度控制。此 IP 计数在 nginx shared memory 中完成,故作用域是每 server 机器,而非每 server worker 进程。
  • 通过 nginx 核心模块 limit_zone 实现对客户端并发请求的控制。
  • 通过每 worker 已完成请求的计数,定期更新 server worker 进程,以绕过任何可能的 server 内存泄漏。

[编辑] 丰富而统一的 REST 接口

将坚持原 OpenResty 的基于 HTTP 方法和 URL 固定层级(4级)的 API 设计风格。可直接通过 web service 对已有接口进行脚本编程,或者对后端进行 SQL 等语言的编程。

[编辑] Server 端可编程与可扩展性

同时能支持 server 端的多语言脚本扩展(LuaV8 JavaScript)。

  • 特别地,在 Lua 语言级别上实现类似 Erlang 那样的透明 I/O 复用模型,从而能在 OpenResty Lua 脚本中实现与 nginx 的事件模型整合在一起的 I/O 复用,同时不用改变原先阻塞式 I/O 的 Lua 代码的写法。
  • 在 V8 JavaScript 中则将尝试提供显式的和 nginx 的事件模型整合在一起的异步 I/O 接口。

注: PHP 内嵌支持优先级较低,因为其性能确实远不及 Lua 和 V8 :)

对于 Lua,为每一个 request session 创建一个独立的 vm 实例。

[编辑] 可伸缩性

可以很方便地在一台 PC 或者 laptop 上安装和运行,也可以轻松扩展到许多台多核生产机。

[编辑] 实现语言和形式

使用 100% C 语言,通过 nginx C module 的形式来实现。

[编辑] 集群体系结构

openresty 集群将由 openresty server 集群, asyncworker 集群, tokyo tyrant server 集群组成。

[编辑] openresty server 集群

由运行 nginx with mod_openresty 这个 HTTP 服务器的机器组成。一般地,同一种后端配置的 openresty server 可以无差别地挂在 LVS 这样的负载平衡器的后面。只要后端连接数允许,这一层的 openresty server 可以线性扩展。

[编辑] tokyo tyrant server 集群

tokyo tyrant 是一种高性能的键值对存储系统 tokyo cabinet 的 web 服务器。我们在这里将只使用 tokyo tyrant 的 memcached 接口。mod_openresty 将利用 tokyo tyrant 集群来存储其自身的元数据,以及作为后端存储的一些元数据的缓存。

特别地,mod_openresty 的 File API 还将支持使用 tokyo tyrant 集群来存储各种类型的用户文件,如几 MB 大小的图片、声音以及其他静态文件。详情见 File API. 更大的附件文件存储将通过 OpenResty 的 BigFile API 来实成,后端实现是一种高性能的开源分布式文件系统 mogilefs.

[编辑] asyncworker 集群

该集群的机器上运行着一种没有 web 端口服务的多 worker daemon 程序,以及分布式队列 memcacheq

[编辑] asyncworker 守护进程

它负责从异步任务队列中取出来自 openresty 异步 View 调用的后端请求,然后执行之。在执行过程中,如果后端支持,将能及时把状态更新给前端的 openresty 的 Job API. 特别地,它还会及时响应 openresty Job API 的任务取消请求。

[编辑] 数据流及消息传递

openresty server 向 asyncworker 传递消息是通过 memcacheq 以及 tokyo tyrant 集群来完成的。而 asyncworker 通过 tokyo tyrant 集群来向 openresty server 更新其 job 完成状态,以及发布最终的请求结果数据。

[编辑] openresty server 内部设计

[编辑] 模块组成

初步将由 nginx-openresty, nginx-openresty-memcached, nginx-openresty-mysql, 和 nginx-openresty-oracle 这几个 nginx C 模块组成。

[编辑] nginx-openresty

这是一个与具体后端,以及具体 API Handler 无关的 openresty 核心。它主要负责对进来的 HTTP 请求进行帐户和角色认证、cookie 处理、URL 解析以及到后端 handler 的调度,以及输入格式的解析和输出数据的格式化。

特别地,nginx-openresty 将提供自己的插件机制,允许用户方便地添加新的 nginx C/C++ 模块级别上的后端驱动实现,一个例子是 nginx-openresty-pgsql.

[编辑] nginx-better-memcached

这将基于 nginx 核心模块 memcached改进而成(正如其名所暗示的)。

主要的新功能如下:

  • 添加按 key 进行多 memcached server 哈希分布;
  • 同时实现基于 POST 的 memcached_add 操作,能支持基于 multipart/form-data 的原始 HTML 表单上传文件请求;
  • 实现基于 PUT 的 memcached_set 操作;
  • 以及实现基于 DELETE 的 memcached_delete 操作。

主要用途是供 nginx-openresty 通过 subrequest 方式利用此模块去和外部的 memcached 服务进行交互(例如指向 tokyotyrant 集群)。

此模块将可以脱离 openresty 独立使用。

[编辑] nginx-openresty-mysql

通过 mysql 异步请求 C 客户端库 libdrizzle 取得底层的 socket 文件描述符,加入到 nginx 底层的 event 模型中。同时实现每 worker 进程的 mysql 连接池,利用 nginx core 的 worker_connections 来保证 mysql 连接数上限不被超过(同时也保证了超过连接数上限的请求也不会被 nginx worker 所接受),并在流量回落时释放 idle 时间足够长的 mysql 连接(s可利用队列来完成这里的连接池的调度)。

如果客户端支持动态改变当前 mysql 用户的话,openresty 的 account 名将映射到 mysql 的帐户名。Model API 将能自动识别所有 mysql 数据表和 mysql 视图。View API 支持 mysql 的 SQL,并支持 View 参数的嵌入记法(即 View 的 query 属性)。

[编辑] nginx-openresty-oracle

将 OCI instant client 底层和 Oracle 数据库通信的 socket 文件描述符拿到,然后注册到 Nginx 的事件模型中。

[编辑] REST API 的主要变化

[编辑] HTTP 请求的方法置换

不再允许用 HTTP GET 请求来摸拟 POST/PUT/DELETE 请求。GET 请求只能用来模拟 HEAD 请求(在跨域 AJAX 的上下文中经常会需要这么做)。而 PUT/DELETE 请求只允许用 POST 来请求。特别地,用 POST 模拟 DELETE 请求时,HTTP content 输入(如果有的话)会被简单忽略。

具体做法是通过内建 URL 参数 _method 来完成。一个例子是:

 POST /=/model/cats/id/3?_method=PUT
 { "age": 5 }

等价于

 PUT /=/model/cats/id/3
 { "age": 5 }

GET 方法不再允许进行 POST/PUT/DELETE 方法的摸拟,以降低跨站攻击(XSS)的风险。

GET 模拟 HEAD 也是用 _method 参数来指定,一个例子是:

 GET /=/view/cats/~/~?_method=HEAD

等价于

 HEAD /=/view/cats/~/~

[编辑] Model API

[编辑] 行筛选的普通模式和运算符模式

相比目前的 OpenResty.pm,Model API 将支持更加丰富的行筛选(获取 model row 数据),例如:

 GET /=/model/cats/~/~?age=gt:3&name=contains:Amy&_op=1

如果后端是 mysql 的话,openresyt server 会自动生成类似下面的 SQL 查询:

 select * from cats where age > 3 and name like '%Amy%';

上面参数设定中的 _op=1 为运算符开关,如果未设定 _op 或设为 0 则将使用普通模式解析查询条件, 比如 age=3 将解析成 age = 3,

 GET /=/model/cats/id/5

将解析为:

 select * from cats where id = 5;

在设定开启运算符后,查询条件将使用 name=op:value 的模式, 其中 op 可为空(当作 eq 运算符处理),但是 : 分割符不可省略。 op 为可自定义的运算符,如 eq, gt, lt, contains 等。

请求字符串中除了常规的 column 查询条件以外,还可以指定以下特殊条件:

 _cols
 _order_by
 _group_by
 _limit

默认情况下 GET 会返回所有 column,通过设置 _cols 来指定要返回的 column 项,如:

 GET /=/model/cats/age/gt:3?_cols=count:id,color&_group_by=color&_op=1

对应查询为:

 select count(id), color from cats where age > 3 group by color;

其他条件的使用跟 sql 语法类似:

 GET /=/model/cats/name/contains:Amy?_cols=age,color&_order_by=age,-id&_limit=10,10&_op=1

翻译为 mysql 为:

 select age, color from cats where name LIKE '%Amy%' order by age, id desc limit 10, 10;


[编辑] View API

不同于原先 OpenResty.pm 中的 OpenResty View API 的设计,新版 View API 的主要变化是

  • 取消了 restyscript minisql 语言。definition 属性被重命名为 query,其内容成为一种带特殊占位的模板语言,具体的查询语言由后端驱动自己解释和处理。而特殊占位则同时定义了 View 对象的参数的名字、类型以及可选的 checker 合法性验证器。
  • 通过新属性 query_lang 可以自己指定 query 的背景语言种类,如果后端支持多种查询语言的话。
  • 通过新属性 async 可以指定"异步 View",其调用仅产生出一个 Job ID,且立即将之返回给客户端,然后由客户端自己通过此 Job ID 向 OpenResty Job API 查询任务的当前完成状态,以及在任务完成后取得结果。
  • 通过新属性 map_to 可以自动建立从 OpenResty View 对象到后端对象的映射关系,例如建立到 RDBMS 后端的函数的映射。
  • 通过新属性 params_checker 可以使用 Lua 这样的动态语言定义对 View 各参数的合法性验证器(如果扩展脚本功能在 openresty server 配置文件中被启用的话)。

[编辑] View 对象的 query 属性

OpenResty View 对象支持 query 属性。它本质上是一种模板语言,通过 $(...) 这种特殊结构,在后端的查询语言中嵌入了 View 自己的参数占位符,连同该参数的相关定义。下面是一个后端查询语言为 SQL(或其某一变种)的 View query 的实例:

  select name, age from persons where name = $(name type=text) and age = $(age type=integer);

于是这里的变量 name 和 age 都将被识别为 View 的形式参数,同时它们的类型分别是文本(text)和整数(integer)。

同时指定自己在 openresty 层面的参数验证器,也是可能的,例如

  select * from animals where age > $(age type=integer checker="return age >= 0 and age <= 100")

这里假设 checker 后端配置使用的是 Lua 解释器或者 LuaJIT. 在上例中,当 age 这个 view 参数的值不在 0 ~ 100 之间,则 openresty 直接向客户端报错,而不会发生 DB 请求。上例中,OpenResty 在 age 值非法时,会返回

  {"success":false,"errstr":"View argument \"age\" failed the validator","errcode":21}


同时提供额外的出错信息也是可能的,通过在 View 定义中指定 checker_errstr 选项:

  select * from animals where age >
     $(age type=integer checker="return age >= 0 and age <= 100" checker_errstr="age须在0到100之间")

于是当 age 不在 0 到 100 之间时,OpenResty 会返回更具体的提示:

  {"success":false,"errstr":"View argument \"age\" failed the validator: age须在0到100之间","errcode":21}

这里的 checker 只能引用当前 View 参数的名字,如果需要编写涉及多个 View 参数的 checker,请使用 View 对象的 params_checker 属性。

上例中的 Lua 代码片中显式的 return 总是需要的。因为 openresty 会自动生成 Lua 函数包裹,例如 return age >= 0 and age <= 100 会被封装成下面的 Lua 函数:

 function xxxx_age_checker (age) return age >= 0 and age <= 100 end

checker 亦可包含多条 Lua 语句,执行条件判断、赋值,甚至循环。下面是一个赋值的例子:

可以写多 Lua 语句,例如:

  tmp = age - 5 return tmp >= 0 and tmp <= 100

在后台会被包装为 Lua 函数

  function xxxx_age_checker(age) tmp = age - 5 return tmp >= 0 and

tmp <= 100 end

值得一提的是,对于禁用了 Lua/V8 等动态语言扩展的 openresty server, checker 和 checker_errstr (连同 View 对象的 params_checker 属性)都是空操作(no-op),此时 OpenResty 鼓励用户尽可能在后端通过类似存储过程这样的东西,在 DB 端对参数进行验证。

对于 mysql 后端而言,query 的“背景语言”就是 mysql 自己的 SQL;而对于 oracle 后端来说,则是 PL/SQL;对于 Pg 后端而言,则有多种可能(可以通过 View 对象的 query_lang 属性加以显式设置),默认为 PL/SQL. 类似地,Hive 后端对应的查询语言则是 Hive SQL.

[编辑] View 对象的 params_checker 属性

该属性在 Lua/V8 动态语言扩展启用时,会将指定的 Lua/V8 语言编写的代码片段作为 View 调用时所进行的参数验证器。在这样的代码片段可以引用所有的 View 参数。一个例子是:

  "params_checker":"return age >= 0 and age <= 100 or string.find(name, 'amy') >= 0"

上例中我们在 checker 中同时引用了 age 和 name 这两个 View 参数。

[编辑] View 对象的 async 属性

当 View 对象的 async 属性置为 true 时,会使得对该 View 对象的查询,直接导致 openresty 将对应的 DB 请求作为任务推入到 memcacheq 任务队列中,供 asyncworker 在后台慢慢执行。openresty 在将任务入队之后,立即返回该任务对应的任务号(Job ID);用户随后可以自己通过此 Job ID 向 OpenResty Job API 查询任务的完成情况和当前状态,并能从 Job API 取得任务的结果。

memcacheq 任务队列会设置上限,故当任务队列满时,openresty 的任务入队操作会失败(在 memcached 协议层返回 NOT STORED 异常),此时 openresty 将返回给用户出错信息。用户或者管理员应当通过 Job API 去取消废弃了但还在执行的 Job.

async 属性的默认值为 false.

[编辑] View 对象的 cached 属性

该属性控制 View 对象的结果集是否进行缓存。当为 true 时,openresty 将尝试把结果集缓存在 TokyoTyrant 这样的持续存储中(或者其他指定的存储系统)。对于 async 属性为真的 View 对象,通过 Job API 获取的结果集亦将被正确地缓存。

缓存的时间长短总是由 expire 属性控制。

缓存时使用的 key 为 View 对象名加上实际提供的 View 参数列表。所以如果 View 的实参不一样,则会缓存同一个 View 的多个副本的结果集。

cached 属性默认为 false.

[编辑] View 对象的 expire 属性

expire 属性控制 View 对象调用后的结果集被缓存的时间。当其值为简单数值时,单位默认为 sec. 同时亦支持文字描述的写法,例如:

  "expire":"1 day 2 hour"

或者指定为永不过期:

  "expire": "never"

当然,View 对象的结果集总是可以被有权限的用户通过 HTTP HEAD 请求强制刷新,例如:

   HEAD /=/view/MyFriends/~/~

[编辑] View 对象的 map_to 属性

View 对象的 map_to 属性用于指定将当前 View 对象直接映射到后端存储的某一个对象。此属性与 View 对象的 query 属性是互斥的。

在 RDBMS 后端的上下文中,map_to 将被映射为指定的 DB function 的名字。OpenResty 会自动查询后端 DB 的系统表,得到目标 DB function 的原型定义(在支持函数重载的后端 DB 中,同一名字的 DB 函数可能有多种原型定义),并缓存在 OpenResty 自身的元数据存储中,并可能在 server 进程内部进行 shm 级别上的进一步缓存。所以每次调用此种类型的 OpenResty View 时,并不会多一次对 DB 的系统表的查询。如果当 DB 中的函数定义发生变化时,有权限的用户应当通过 HTTP HEAD 命令强制 OpenResty 重新从后端更新相关元数据以及清除各级缓存,例如下面这个例子

 HEAD /=/view/MyFriends

将更新 MyFriends 这个 View 对象的相关元数据。

对 Oracle 和 PostgreSQL 这样支持名字空间的后端而言,在 map_to 属性中指定名字空间名也是允许的,例如:

 map_to="mypackage.myfunc"

除非此特性在配置文件中被显式禁用。

[编辑] Action API

Action API 与 View API 非常接近,最主要的区别仅在于 Action API 不返回结果集,而是某一个操作的结果。在 RDBMS 后端的上下文中,View API 的 query 是通过 DB 的 query 方式执行的,而 Action API 则是通过 DB 的 do 方式执行。因此 Action 对象此上下文中,调用的结果类似下面这个样子:

 {"success":true,"rows_affected":100}

和原先 OpenResty.pm 的 Action API 不同的是,不再有 definition 属性,也不再有 restyscript 语言层。(restyscript 语言的一个去 minisql 的改进版本将在 Batch API 中提供。)

这里涉及的另一个细节是,在以 JSON output filter 作为结果输出时,"success" 属性将为 JSON 中的布尔值 true 和 false. 原先 OpenResty.pm 是返回的 C 风格的真假值 0 和 1。但后来发现在 Haskell 这样的类型严格的客户端编程语言中,JSON 库返回的 success 字段的值如不是严格的布尔类型,就不能直接用于 if 语句这样的表达式,于是须写为类似

   if (res.success != 0) { ... }

这样的形式,呵呵。所以我希望在新版 OpenResty 接口中能纠正这个错误 :)

Action 对象与 View 对象一样拥有下面这些属性:

[编辑] Action 对象的 query 属性

和 View 完全类似。一个 SQL 后端上下文中的例子是:

 update cats set age = 23 where name = $(name type=text default="Tom");

query_lang 属性在一些后端中亦是有意义的。

[编辑] Action 对象的 params_checker 属性

同 View 对象的 params_checker 属性。

[编辑] Action 对象的 async 属性

含义与 View 对象同。

[编辑] Action 对象的 map_to 属性

与 View 对象相近。在 RDBMS 的上下文中,可以映射到 DB 存储过程,或者 DB 函数。在后种情况下,DB 函数的结果集返回值将被忽略。

与 View 不同的是,Action 对象不支持 cached 和 expire 属性。

[编辑] Batch API

此 API 提供了一种 OpenResty service 级别上的批处理编程。

它可以支持两种语言:

1. 使用 restyscript 语言(在原 OpenResty.pm 基础上去除了 minisql 部分,新增 if/else 条件语句),一个例子是:

   get('/=/view/myfriends/~/~', name:$(name), op:contains);
   if ($(content)) {
     post('/=/model/posts/~/~', { name:$(name), body:$(content) });
   }

2. 使用 lua 语言,封装 restyscript 语言中的 get/post/delete/put 等原语,并自动转为异步 I/O.

所有涉及本地后端的操作都将置于一个后端 transaction 中(如果后端支持 transaction 的话)。

[编辑] Role API

Role API 相比 OpenResty.pm 无明显变化。

[编辑] Captcha API

相比 OpenResty.pm 无明显变化。

[编辑] Login API

主要变化是:

  • 当登录方式为 password 时,要求 OpenResty 角色在登录时,必需先通过 HTTP 请求
   GET /=/login/salt

取得 server 端生成并暂存的一随机串。然后以此随机串为 salt 对用户自己的口令明文作 3 遍 md5 计算:

 passwd = md5(passwd)
 for 1..2 do
    passwd = md5(passwd + salt)
 done

上面的伪代码中的 + 表示字符串拼接操作。然后我们再用得到的 passwd 值作为 _pass 参数的值进行登录,例如:

  GET /=/login/session/_user/agentzh.Admin?_pass=c59e386da2fe0e30ef9b7de82f9b6539

注意原 OpenResty.pm 中使用的密码参数名叫做 _password,现缩写为 _pass.

作为 salt 的随机数是有使用期限的,在登录操作成功后不久则过期。且登录成功后返回的 session ID 会跟客户端的 IP 地址直接绑定。所以如果 IP 地址不正确, session ID 也被认为是非法的,从而拒掉登录请求。

[编辑] Job API

用于管理异步任务,比如异步 View 和异步 Action 调用对应的 DB 查询会话。

[编辑] 查看所有活动的任务

 GET /=/job

[编辑] 删除或取消所有活动的任务

 DELETE /=/job

[编辑] 查询某个任务的状态

 GET /=/job/foobarbaz

这里的 foobarbaz 为某一 job 的 ID。一个 openresty server 的返回结果的例子是:

 {"status":"done"}

或者

 {"status":"busy","elapsed":"3 hour 2 min 25 sec"}

或者

 {"status":"pending"}

最后一种状态是未被 syncworker 从任务队列中取得,即尚未真正开做。

[编辑] 取得某个已完成任务的结果

 GET /=/job/foobarbaz/~/~

这里的 foobarbaz 同样为某一 job 的 ID。

[编辑] 删除或者取消某一任务

 DELETE /=/job/foobarbaz

[编辑] 清空任务的结果数据但不删除任务

 DELETE /=/job/foobarbaz/~/~

[编辑] Type API

用户可以通过创建 Type 对象,定义自己的 View/Action 参数类型。从而复用某一个常用的 checker.

[编辑] 创建 Type 对象

 POST /=/type/email
 { "def": "return pcre.match(val, '^\w+@\w+(\.\w+)+')" }

这里在 Lua 片段中引用的变量 val 会被自动赋予待测试的值。

创建之后,就可以在 View/Action 对象的 query 定义中使用这个新的 email 类型了,例如:

 POST /=/view/gmailers
 { "query": "select * from contacts where email_addr = $(email_address type=email)" }

Type 对象的 def 里的 Lua 代码都应返回一个布尔值,用以指示当前的取值是否符合当前类型的约束。这与 View/Action 中的参数 checker 里的 Lua 代码是类似的。

[编辑] 测试 Type 对象

 GET /=/type/email/val/agentzh@gmail.com

这里真实的 HTTP 请求串,可能需要对 agentzh@gmail.com 进行 URL 编码 :)

[编辑] 读取所有的 Type 对象

 GET /=/type

[编辑] 删除所有的 Type 对象

 DELETE /=/type

注意内建 type 不会被删除 ;)

[编辑] 删除一个指定的 Type 对象

 DELETE /=/type/email

[编辑] 查看一个已有 Type 对象的定义

 GET /=/type/email

[编辑] Filter API

Filter API 提供了输入和输出两种过滤器。过滤器可以使用 Lua 这样的语言编写。

[编辑] 创建 Filter 对象

 POST /=/filter/my_filter
 {"def":"<lua code goes here>", "type":"out", "buffered":false }

[编辑] 使用 Filter 对象

Filter 以及 Filter 的组合,可以直接作为输入输出格式的名字(即作为 _infmt 和 _outfmt 选项的取值)。例如:

 GET /=/model/cats/~/~?_infmt=my_filter&_outfmt=csv

事实上,json/xml/csv 这样的 _outfmt 取值,其本质也是一种内部 Filter,它们也可以和其他输出 Filter 对象任意组合,例如:

 GET /=/model/cats/~/~?_outfmt=csv+my_validating_filter&_outfmt=xml

输入和输出 Filter 都是以数据块的形式工作的,但 Filter 对象自身可以在 Lua 空间中通过持续化变量来维护自己的状态。

对于带完全 buffer 的输出 Filter,可以出错时,直接抛出异常,中断数据流,返回给客户端错误消息。所以对输入和输出的合法性验证逻辑亦可放在带完全 buffer 的自定义 Filter 中。

测试输入/输出 Filter 可以利用下面的请求:

 PUT /=/filter/my_filter/~/~
 <data here>

[编辑] Template API

本质上相当于 buffered 属性为 true 的 Output Filter,但其输入数据不是一份一份给的,而是整块。特别地,Template API 自身可以指定一个或者多个 View 对象作为数据源。Template 对象的定义为一 TT2 模板(模板记法与 Perl Template ToolKit 和 Jemplate 一致)。

[编辑] Feed API

Feed 对象本质上是一种内部定义的 Template 对象,它由特定的 View 作为数据源驱动,生成对应的 RSS/Atom 格式的 XML 输出。

[编辑] Trigger API

Trigger 对象和 Filter 对象一样,接受一个 Lua/V8 代码片段作为定义,然后在指定的操作模式发生前后,执行那段代码。一个例子是

 POST /=/trigger/my_logger
 { "method": "GET",
   "url": "/=/model/~/~/~",
   "resty.log('Getting rows from model ' .. resty.urlsegs[2])",
   "when": "before" }

这样,凡是在 GET /=/model/Foo/~/~ 这样的请求执行之前就会写一行 log. 更有趣的动作是触发其他 OpenResty 子请求,例如:

 POST /=/trigger/my_logger
 { "method": "POST",
   "url": "/=/model/Comments/~/~",
   "resty.post('/=/action/Blah/~/~')",
   "when": "after" }

[编辑] File API

用于附件文件上传和下载 API

[编辑] 查看所有的附件

 GET /=/file

[编辑] 删除所有的附件

 DELETE /=/file

[编辑] 下载某一个附件

 GET /=/file/my_photos.rar/~/~

[编辑] 上传某一个附件

 POST /=/file/my_photos.tar
 <the file content>

同时也支持 HTML 表单的 multipart/form-data 方式的直接文件上传。

File API 多用于几 MB 以内的文件的存储,更大的文件当使用 BigFile API.

[编辑] Chart API

Chart API 将允许用户以一个或者多个 View 作为数据源,绘制出类似 Google Chart API 中的各种形式的图表,返回 PNG 或者 Gif 格式的图片文件。

[编辑] Handler API

Handler API 允许用户通过 Lua 这样的动态语言直接定义新的 OpenResty Handler 的实现,比如创建一个新的 Foo API (/=/foo/).

[编辑] Mail API

或许可以 subrequest 到 nginx 的 mail 模块,从而自动取得对 IMAP,POP3,和 SMTP 协议的支持。具体 API 设计待定 :)

[编辑] 参考资料

Personal tools