@@ -871,7 +871,7 @@ autoindex on;
871871
872872!!! note "使用一个专门的后端程序生成文件列表页面"
873873
874- 你可能会希望使用其他的文件列表程序(例如 [h5ai](https://github.com/lrsjng/h5ai)),同时在用户访问文件时让 Nginx 直接提供,而不是让后端程序处理文件下载请求。以下是一个参考配置,视具体的文件列表程序,可能需要做一些调整:
874+ 你可能会希望使用其他的文件列表程序(例如 [h5ai](https://github.com/lrsjng/h5ai),或者我们编写的用于科大镜像站的 [yadex](https://github.com/ustclug/yadex) ),同时在用户访问文件时让 Nginx 直接提供,而不是让后端程序处理文件下载请求。以下是一个参考配置,视具体的文件列表程序,可能需要做一些调整:
875875
876876 ```nginx
877877 root /var/www/files/;
@@ -1278,13 +1278,13 @@ print(decoded["key1"])
12781278``` lua
12791279local _M = {}
12801280
1281- local function some_internal_func (a )
1281+ local function double_var (a )
12821282 return a + a
12831283end
12841284
1285- function _M .f1 (a , b )
1286- local aa = some_internal_func (a )
1287- local bb = some_internal_func (b )
1285+ function _M .double_plus (a , b )
1286+ local aa = double_var (a )
1287+ local bb = double_var (b )
12881288 return aa + bb
12891289end
12901290
@@ -1314,6 +1314,96 @@ location / {
13141314
13151315其中 [ ` content_by_lua_block ` ] ( https://github.com/openresty/lua-nginx-module?tab=readme-ov-file#content_by_lua_block ) 控制了请求的响应内容,而 [ ` ngx.say ` ] ( https://github.com/openresty/lua-nginx-module?tab=readme-ov-file#ngxsay ) 则会直接向响应中写入内容。
13161316
1317+ ### 执行阶段 {#execution-phases}
1318+
1319+ 有一张经典的图展示了 Nginx 处理请求的各个阶段中,Lua 脚本可以插入的位置:
1320+
1321+ ![ Order of Lua Nginx Module Directives] ( https://cloud.githubusercontent.com/assets/2137369/15272097/77d1c09e-1a37-11e6-97ef-d9767035fc3e.png )
1322+
1323+ /// caption
1324+ 图来自 [ openresty/lua-nginx-module] ( https://github.com/openresty/lua-nginx-module ) 仓库
1325+ ///
1326+
1327+ 有关 Nginx 处理请求的各个阶段的介绍,可以参考 [ Nginx 的 Development guide] ( https://nginx.org/en/docs/dev/development_guide.html#http_phases ) 。
1328+
1329+ 如果不熟悉相关的阶段的话,那么在写代码的时候可能会遇到非预期的行为。这是一个我们实际遇到的例子:
1330+
1331+ ``` nginx
1332+ server {
1333+ # ...
1334+
1335+ access_by_lua_file /etc/nginx/lua/access.lua;
1336+ header_filter_by_lua_file /etc/nginx/lua/header_filter.lua;
1337+ log_by_lua_file /etc/nginx/lua/log.lua;
1338+
1339+ location /lua-test0 {
1340+ return 200;
1341+ }
1342+
1343+ location /lua-test1 {
1344+ try_files $uri $uri/ =404;
1345+ }
1346+ }
1347+ ```
1348+
1349+ 那么在访问 ` /lua-test0 ` 的时候,上面三个 Lua 脚本都会被执行吗?` /lua-test1 ` 呢?答案是:对 ` /lua-test1 ` ,这三个脚本都会被执行,但是对 ` /lua-test0 ` ,` access_by_lua_file ` 不会被执行,其他两个会。这是因为 ` return ` 在 rewrite 阶段执行重定向,结束了对请求的处理,因此后面的 access 阶段的脚本不会被执行。但是 header_filter(输出过滤的一部分,未在 Phase 中列出,但是会在 content 生成后,发送数据前执行)和 log(日志记录)阶段仍然会被执行,因此就产生了和上图矛盾的现象。
1350+
1351+ ### 存储与共享状态 {#storing-state}
1352+
1353+ 在编写脚本时我们常见的需求有:
1354+
1355+ - 在某个阶段存储的状态需要在后续的阶段使用
1356+ - 多个 worker 进程之间需要共享状态
1357+
1358+ 以下介绍 Lua 模块提供解决方案。
1359+
1360+ #### ` ngx.ctx ` 与 ` ngx.var ` {#ngx-ctx-ngx-var}
1361+
1362+ [ ` ngx.ctx ` ] ( https://github.com/openresty/lua-nginx-module?tab=readme-ov-file#ngxctx ) 是可以存储任意 Lua 变量的表,在当前请求有效。使用方法类似如下:
1363+
1364+ ``` nginx
1365+ location /example {
1366+ access_by_lua_block {
1367+ ngx.ctx.start_time = ngx.now()
1368+ ngx.sleep(0.1)
1369+ }
1370+
1371+ log_by_lua_block {
1372+ local duration = ngx.now() - ngx.ctx.start_time
1373+ ngx.log(ngx.ERR, "Request took " .. duration .. " seconds")
1374+ }
1375+ }
1376+ ```
1377+
1378+ 可以看到,这里在 access 阶段存储了请求的开始时间,并在 log 阶段计算并输出了请求的持续时间。
1379+
1380+ 不过有一个无法忽视的问题是:如果请求使用了内部跳转(internal redirect,例如 ` try_files ` 、` error_page ` 、` index ` ),那么 ` ngx.ctx ` 会被清空。因此,退而求其次,需要使用 Nginx 的变量机制来存储数据。可以使用 [ ` ngx.var.VARIABLE ` ] ( https://github.com/openresty/lua-nginx-module?tab=readme-ov-file#ngxvarvariable ) 来访问 Nginx 变量,不过 ` ngx.var ` 相比 ` ngx.ctx ` 有一些限制:
1381+
1382+ - 性能相比 ` ngx.ctx ` 较差。
1383+ - 每次访问 ` ngx.var ` 都会产生一次内存分配,因此编程时需要先获取到本地变量再使用。
1384+ - ` ngx.var ` 只能存储字符串或数字。
1385+ - 需要提前使用 ` set ` 定义变量。
1386+
1387+ 对于需要使用 ` ngx.var ` 存储复杂 Lua 变量的场景,可以使用第三方的 [ lua-resty-ctxdump] ( https://github.com/tokers/lua-resty-ctxdump/ ) 。其原理是:将实际内容保存在模块内部的 ` memo ` 表中,而需要存储在 ` ngx.var ` 里面的只是 ` memo ` 表的 key(数字)。
1388+
1389+ #### 共享 dict {#shared-dict}
1390+
1391+ 针对不同的工作进程之间需要共享状态的场景(例如统计某个 ` location ` 的访问状态),Lua 模块提供了 [ ` lua_shared_dict ` ] ( https://github.com/openresty/lua-nginx-module?tab=readme-ov-file#lua_shared_dict ) 指令,可以在 ` http ` 块中定义一个共享 dict 区域:
1392+
1393+ ``` nginx
1394+ http {
1395+ lua_shared_dict my_cache 10m; # 定义一个名字为 my_cache 的共享 dict,大小 10M。
1396+ }
1397+ ```
1398+
1399+ 在 Lua 代码中使用 [ ` ngx.shared.DICT ` ] ( https://github.com/openresty/lua-nginx-module?tab=readme-ov-file#ngxshareddict ) 调用。
1400+
1401+ !!! lab "获取共享 dict 的剩余空间"
1402+
1403+ 对比较复杂的需求场景下,获取共享 dict 的剩余空间是有必要的——可以据此添加监控告警,防止共享 dict 被写满导致服务异常。请编写一个 Lua 脚本,当用户访问 `/shared-dict-info` 时,返回共享 dict 的总大小和剩余空间。
1404+
1405+ 如果需要测试,可能还需要添加一些其他的 `location` 来向共享 dict 中写入/删除数据。
1406+
13171407## 示例介绍 {#examples}
13181408
13191409<!-- 以下给出一些实践中会使用的 Nginx 配置示例。
0 commit comments