Spec-Zone.ru › nginx / Lua Module

ngx_http_lua_module

Название

ngx_http_lua_module — встраивание возможностей Lua в HTTP-серверы Nginx.

Этот модуль — основной компонент OpenResty. Если вы используете этот модуль, значит, по сути, вы используете OpenResty :)

Этот модуль не распространяется вместе с исходным кодом Nginx. См. инструкции по установке.

Содержание

  • Название
  • Статус
  • Версия
  • Видео
  • Краткий обзор
  • Описание
  • Типичные варианты использования
  • Совместимость с Nginx
  • Установка
    • Сборка в виде динамического модуля
    • Настройки макросов C
  • Сообщество
    • Список рассылки на английском языке
    • Список рассылки на китайском языке
  • Репозиторий кода
  • Ошибки и исправления
  • Поддержка байт-кода LuaJIT
  • Поддержка системных переменных окружения
  • Поддержка HTTP 1.0
  • Статическая компоновка модулей на чистом Lua
  • Совместное использование данных в рамках рабочего процесса Nginx
  • Известные проблемы
    • Проблемы с подключением TCP-сокета
    • Приостановка и возобновление корутин Lua
    • Область видимости переменных Lua
    • Локации, настроенные директивами подзапросов других модулей
    • Cosocket доступны не везде
    • Специальные последовательности экранирования
    • Совместное использование с SSI не поддерживается
    • Режим SPDY поддерживается не полностью
    • Отсутствие данных в запросах, обработка которых прерывается досрочно
  • Список задач
  • Изменения
  • Набор тестов
  • Авторские права и лицензия
  • См. также
  • Директивы
  • API Nginx для Lua
  • Устаревшие разделы
    • Специальные последовательности PCRE
    • Поддержка байт-кода Lua/LuaJIT

Статус

Готов к эксплуатации в производственной среде.

Версия

В этом документе описан ngx_lua v0.10.25, выпущенный 19 июня 2023 года.

Видео

  • Видео на YouTube «Пример Hello World HTTP с OpenResty/Lua»

    Hello World HTTP Example with OpenResty/Lua

  • Видео на YouTube «Создание собственных модулей Lua для приложений OpenResty/Nginx»

    Write Your Own Lua Modules in OpenResty/Nginx Applications

  • Видео на YouTube «Демонстрация утилиты командной строки resty в OpenResty»

    OpenResty's resty Command-Line Utility Demo

  • Видео на YouTube «Правильное измерение времени выполнения кода Lua в OpenResty»

    Measure Execution Time of Lua Code Correctly in OpenResty

  • Видео на YouTube «Предварительная компиляция модулей Lua в байт-код LuaJIT для ускорения запуска OpenResty»

    Precompile Lua Modules into LuaJIT Bytecode to Speedup OpenResty Startup

Подписывайтесь на наш официальный канал OpenResty на YouTube.

Краткий обзор

# set search paths for pure Lua external libraries (';;' is the default path):
lua_package_path '/foo/bar/?.lua;/blah/?.lua;;';

# set search paths for Lua external libraries written in C (can also use ';;'):
lua_package_cpath '/bar/baz/?.so;/blah/blah/?.so;;';

server {
    location /lua_content {
        # MIME type determined by default_type:
        default_type 'text/plain';

        content_by_lua_block {
            ngx.say('Hello,world!')
        }
    }

    location /nginx_var {
        # MIME type determined by default_type:
        default_type 'text/plain';

        # try access /nginx_var?a=hello,world
        content_by_lua_block {
            ngx.say(ngx.var.arg_a)
        }
    }

    location = /request_body {
        client_max_body_size 50k;
        client_body_buffer_size 50k;

        content_by_lua_block {
            ngx.req.read_body()  -- explicitly read the req body
            local data = ngx.req.get_body_data()
            if data then
                ngx.say("body data:")
                ngx.print(data)
                return
            end

            -- body may get buffered in a temp file:
            local file = ngx.req.get_body_file()
            if file then
                ngx.say("body is in file ", file)
            else
                ngx.say("no body found")
            end
        }
    }

    # transparent non-blocking I/O in Lua via subrequests
    # (well, a better way is to use cosockets)
    location = /lua {
        # MIME type determined by default_type:
        default_type 'text/plain';

        content_by_lua_block {
            local res = ngx.location.capture("/some_other_location")
            if res then
                ngx.say("status: ", res.status)
                ngx.say("body:")
                ngx.print(res.body)
            end
        }
    }

    location = /foo {
        rewrite_by_lua_block {
            res = ngx.location.capture("/memc",
                { args = { cmd = "incr", key = ngx.var.uri } }
            )
        }

        proxy_pass http://blah.blah.com;
    }

    location = /mixed {
        rewrite_by_lua_file /path/to/rewrite.lua;
        access_by_lua_file /path/to/access.lua;
        content_by_lua_file /path/to/content.lua;
    }

    # use nginx var in code path
    # CAUTION: contents in nginx var must be carefully filtered,
    # otherwise there'll be great security risk!
    location ~ ^/app/([-_a-zA-Z0-9/]+) {
        set $path $1;
        content_by_lua_file /path/to/lua/app/root/$path.lua;
    }

    location / {
       client_max_body_size 100k;
       client_body_buffer_size 100k;

       access_by_lua_block {
           -- check the client IP address is in our black list
           if ngx.var.remote_addr == "132.5.72.3" then
               ngx.exit(ngx.HTTP_FORBIDDEN)
           end

           -- check if the URI contains bad words
           if ngx.var.uri and
                  string.match(ngx.var.request_body, "evil")
           then
               return ngx.redirect("/terms_of_use.html")
           end

           -- tests passed
       }

       # proxy_pass/fastcgi_pass/etc settings
    }
}

Описание

Этот модуль встраивает LuaJIT 2.0/2.1 в Nginx. Это основной компонент OpenResty. Если вы используете этот модуль, значит, по сути, вы используете OpenResty.

Начиная с версии v0.10.16 этого модуля, стандартный интерпретатор Lua (также известный как «PUC-Rio Lua») больше не поддерживается. В этом документе термины «Lua» и «LuaJIT» используются как взаимозаменяемые обозначения интерпретатора LuaJIT.

Используя подзапросы Nginx, этот модуль позволяет интегрировать мощные потоки Lua (известные как «корутины» Lua) в событийную модель Nginx.

В отличие от mod_lua Apache и mod_magnet Lighttpd, код Lua, выполняемый с помощью этого модуля, может быть полностью неблокирующим при работе с сетевым трафиком, если для обработки запросов к вышестоящим сервисам, таким как MySQL, PostgreSQL, Memcached, Redis или вышестоящие HTTP-веб-сервисы, используется предоставляемый модулем API Nginx для Lua.

С этим модулем можно использовать как минимум следующие библиотеки Lua и модули Nginx:

  • lua-resty-memcached
  • lua-resty-mysql
  • lua-resty-redis
  • lua-resty-dns
  • lua-resty-upload
  • lua-resty-websocket
  • lua-resty-lock
  • lua-resty-logger-socket
  • lua-resty-lrucache
  • lua-resty-string
  • ngx_memc
  • ngx_postgres
  • ngx_redis2
  • ngx_redis
  • ngx_proxy
  • ngx_fastcgi

С этим модулем ngx_lua можно использовать практически любые модули Nginx с помощью ngx.location.capture или ngx.location.capture_multi, однако рекомендуется использовать эти lua-resty-* библиотеки вместо создания подзапросов для доступа к вышестоящим модулям Nginx, поскольку первые обычно гораздо гибче и эффективнее с точки зрения использования памяти.

Интерпретатор Lua (также известный как «состояние Lua» или «экземпляр виртуальной машины LuaJIT») используется совместно всеми запросами в одном рабочем процессе Nginx, чтобы минимизировать потребление памяти. Контексты запросов изолированы друг от друга с помощью легковесных корутин Lua.

Загруженные модули Lua сохраняются на уровне рабочего процесса Nginx, благодаря чему Lua занимает мало памяти даже при высокой нагрузке.

Этот модуль подключается к подсистеме Nginx «http», поэтому поддерживает только протоколы обмена данными с клиентами из семейства HTTP (HTTP 0.9/1.0/1.1/2.0, WebSockets и т. д.). Если вам нужна универсальная передача данных по TCP с клиентами, используйте модуль ngx_stream_lua, предоставляющий совместимый API Lua.

Типичные варианты использования

Вот лишь несколько примеров:

  • объединение и обработка в Lua результатов различных вышестоящих модулей Nginx (proxy, drizzle, postgres, redis, memcached и т. д.);
  • реализация любых сложных проверок контроля доступа и безопасности на Lua до того, как запросы достигнут вышестоящих серверов;
  • произвольное изменение заголовков ответа с помощью Lua;
  • получение сведений о серверной части из внешних хранилищ данных (например, redis, memcached, mysql, postgresql) и использование этих сведений для выбора вышестоящего сервера для обращения на лету;
  • создание веб-приложений любой сложности с обработчиком содержимого, используя синхронный, но при этом неблокирующий доступ к базам данных и другим хранилищам;
  • реализация очень сложной диспетчеризации URL на Lua на этапе переписывания;
  • использование Lua для реализации расширенных механизмов кэширования подзапросов и произвольных локаций Nginx.

Возможности безграничны: модуль позволяет объединять различные компоненты Nginx и предоставляет пользователям всю мощь языка Lua. Благодаря LuaJIT 2.x модуль обеспечивает полную гибкость скриптов, сохраняя производительность, сопоставимую с программами на C, как по времени ЦП, так и по объёму используемой памяти.

Другим реализациям скриптовых языков обычно сложно достичь такой производительности.

Совместимость с Nginx

Последняя версия этого модуля совместима со следующими версиями Nginx:

  • 1.25.x (последняя протестированная версия: 1.25.1)
  • 1.21.x (последняя протестированная версия: 1.21.4)
  • 1.19.x (последняя протестированная версия: 1.19.3)
  • 1.17.x (последняя протестированная версия: 1.17.8)
  • 1.15.x (последняя протестированная версия: 1.15.8)
  • 1.14.x
  • 1.13.x (последняя протестированная версия: 1.13.6)
  • 1.12.x
  • 1.11.x (последняя протестированная версия: 1.11.2)
  • 1.10.x
  • 1.9.x (последняя протестированная версия: 1.9.15)
  • 1.8.x
  • 1.7.x (последняя протестированная версия: 1.7.10)
  • 1.6.x

Ядра Nginx версий ниже 1.6.0 (не включая её) не поддерживаются.

Установка

Настоятельно рекомендуется использовать выпуски OpenResty, в состав которых входят Nginx, ngx_lua (этот модуль), LuaJIT, а также другие мощные модули Nginx и библиотеки Lua.

Не рекомендуется самостоятельно собирать этот модуль вместе с Nginx, поскольку правильная настройка сборки может оказаться непростой задачей.

Обратите внимание, что в официальных выпусках Nginx, LuaJIT и OpenSSL есть различные ограничения и давние ошибки, которые могут привести к отключению некоторых функций этого модуля, их некорректной работе или снижению производительности. Рекомендуется использовать официальные выпуски OpenResty, поскольку в них включены оптимизированная ветка LuaJIT 2.1 от OpenResty и исправления для Nginx/OpenSSL.

Также ngx_lua можно вручную скомпилировать в состав Nginx:

  1. LuaJIT можно скачать из последнего выпуска ветки LuaJIT от OpenResty. Также поддерживаются официальные выпуски LuaJIT 2.x, хотя производительность будет значительно ниже по причинам, описанным выше.
  2. Скачайте последнюю версию модуля ngx_devel_kit (NDK) ЗДЕСЬ
  3. Скачайте последнюю версию ngx_lua ЗДЕСЬ
  4. Скачайте последнюю поддерживаемую версию Nginx ЗДЕСЬ (см. раздел «Совместимость с Nginx»).
  5. Скачайте последнюю версию lua-resty-core ЗДЕСЬ
  6. Скачайте последнюю версию lua-resty-lrucache ЗДЕСЬ

Соберите исходный код вместе с этим модулем:

wget 'https://openresty.org/download/nginx-1.19.3.tar.gz'
tar -xzvf nginx-1.19.3.tar.gz
cd nginx-1.19.3/

# tell nginx's build system where to find LuaJIT 2.0:
export LUAJIT_LIB=/path/to/luajit/lib
export LUAJIT_INC=/path/to/luajit/include/luajit-2.0

# tell nginx's build system where to find LuaJIT 2.1:
export LUAJIT_LIB=/path/to/luajit/lib
export LUAJIT_INC=/path/to/luajit/include/luajit-2.1

# Here we assume Nginx is to be installed under /opt/nginx/.
./configure --prefix=/opt/nginx \
        --with-ld-opt="-Wl,-rpath,/path/to/luajit/lib" \
        --add-module=/path/to/ngx_devel_kit \
        --add-module=/path/to/lua-nginx-module

# Note that you may also want to add `./configure` options which are used in your
# current nginx build.
# You can get usually those options using command nginx -V

# you can change the parallelism number 2 below to fit the number of spare CPU cores in your
# machine.
make -j2
make install

# Note that this version of lug-nginx-module not allow to set `lua_load_resty_core off;` any more.
# So, you have to install `lua-resty-core` and `lua-resty-lrucache` manually as below.

cd lua-resty-core
make install PREFIX=/opt/nginx
cd lua-resty-lrucache
make install PREFIX=/opt/nginx

# add necessary `lua_package_path` directive to `nginx.conf`, in the http context

lua_package_path "/opt/nginx/lib/lua/?.lua;;";

Сборка в виде динамического модуля

Начиная с NGINX 1.9.11, этот модуль также можно собрать как динамический модуль, используя параметр --add-dynamic-module=PATH вместо --add-module=PATH в приведённой выше командной строке ./configure. После этого модуль можно явно загрузить в nginx.conf с помощью директивы load_module, например:

load_module /path/to/modules/ndk_http_module.so;  # assuming NDK is built as a dynamic module too
load_module /path/to/modules/ngx_http_lua_module.so;

Настройки макросов C

При сборке этого модуля через OpenResty или вместе с ядром Nginx можно определить следующие макросы C с помощью параметров компилятора C:

  • NGX_LUA_USE_ASSERT При определении этого макроса в кодовой базе ngx_lua на C включаются проверки утверждений. Рекомендуется для сборок, предназначенных для отладки или тестирования. При включении может возникнуть небольшая дополнительная нагрузка во время выполнения. Этот макрос впервые появился в выпуске v0.9.10.
  • NGX_LUA_ABORT_AT_PANIC По умолчанию, если возникает паника виртуальной машины LuaJIT, ngx_lua плавно завершает текущий рабочий процесс nginx. Если задать этот макрос C, ngx_lua немедленно аварийно завершит текущий рабочий процесс nginx (обычно это приводит к созданию файла дампа памяти). Этот параметр полезен для отладки паник виртуальной машины. Впервые он появился в выпуске v0.9.8.

Чтобы включить один или несколько таких макросов, передайте дополнительные параметры компилятора C скрипту ./configure для Nginx или OpenResty. Например:

./configure --with-cc-opt="-DNGX_LUA_USE_ASSERT -DNGX_LUA_ABORT_AT_PANIC"

Сообщество

Список рассылки на английском языке

Список рассылки openresty-en предназначен для англоязычных пользователей.

Список рассылки на китайском языке

Список рассылки openresty предназначен для китайскоязычных пользователей.

Репозиторий кода

Репозиторий кода этого проекта размещён на GitHub: openresty/lua-nginx-module.

Ошибки и исправления

Сообщения об ошибках, пожелания и исправления можно отправить следующим образом:

  1. создать обращение в трекере ошибок GitHub;
  2. или написать в сообщество OpenResty.

Поддержка байт-кода LuaJIT

Посмотрите видео на YouTube «Правильное измерение времени выполнения кода Lua в OpenResty»

Precompile Lua Modules into LuaJIT Bytecode to Speedup OpenResty Startup

Начиная с выпуска v0.5.0rc32, все директивы конфигурации *_by_lua_file (например, content_by_lua_file) поддерживают непосредственную загрузку файлов с необработанным байт-кодом LuaJIT 2.0/2.1:

/path/to/luajit/bin/luajit -b /path/to/input_file.lua /path/to/output_file.ljbc

Параметр -bg можно использовать для включения отладочной информации в файл байт-кода LuaJIT:

/path/to/luajit/bin/luajit -bg /path/to/input_file.lua /path/to/output_file.ljbc

Дополнительные сведения о параметре -b см. в официальной документации LuaJIT:

https://luajit.org/running.html#opt_b

Обратите внимание, что файлы байт-кода, созданные LuaJIT 2.1, несовместимы с LuaJIT 2.0, и наоборот. Поддержка байт-кода LuaJIT 2.1 впервые появилась в ngx_lua v0.9.3.

Попытка загрузить файлы байт-кода стандартной Lua 5.1 в экземпляры ngx_lua, связанные с LuaJIT 2.0/2.1 (или наоборот), приведёт к появлению сообщения об ошибке Nginx, например:

[error] 13909#0: *1 failed to load Lua inlined code: bad byte-code header in /path/to/test_file.luac

Загрузка файлов байт-кода с помощью примитивов Lua, таких как require и dofile, должна всегда работать ожидаемым образом.

Поддержка системных переменных окружения

Если вы хотите обратиться из Lua к системной переменной окружения, например foo, с помощью стандартного API Lua os.getenv, необходимо также указать имя этой переменной окружения в файле nginx.conf с помощью директивы env. Например:

env foo;

Поддержка HTTP 1.0

Протокол HTTP 1.0 не поддерживает передачу данных блоками и для поддержки постоянных соединений HTTP 1.0 требует явного заголовка Content-Length, если тело ответа не пусто. Поэтому при получении запроса HTTP 1.0, когда директива lua_http10_buffering включена on, ngx_lua будет буферизовать вывод вызовов ngx.say и ngx.print, а также отложит отправку заголовков ответа до получения всего тела ответа. После этого ngx_lua сможет вычислить общую длину тела и сформировать подходящий заголовок Content-Length для отправки клиенту HTTP 1.0. Однако если в выполняемом коде Lua задан заголовок ответа Content-Length, буферизация будет отключена, даже если директива lua_http10_buffering включена on.

Для ответов с большим потоковым выводом важно отключить директиву lua_http10_buffering, чтобы свести к минимуму использование памяти.

Обратите внимание, что распространённые инструменты тестирования производительности HTTP, такие как ab и http_load, по умолчанию отправляют запросы HTTP 1.0. Чтобы заставить curl отправлять запросы HTTP 1.0, используйте параметр -0.

Статическая компоновка модулей на чистом Lua

С LuaJIT 2.x можно статически скомпоновать байт-код модулей на чистом Lua с исполняемым файлом Nginx.

С помощью исполняемого файла luajit можно скомпилировать файлы модулей Lua .lua в объектные файлы .o, содержащие экспортированные данные байт-кода, а затем скомпоновать файлы .o непосредственно при сборке Nginx.

Ниже приведён простой пример. Предположим, у нас есть следующий файл .lua с именем foo.lua:

-- foo.lua
local _M = {}

function _M.go()
    print("Hello from foo")
end

return _M

Затем скомпилируем этот файл .lua в файл foo.o:

/path/to/luajit/bin/luajit -bg foo.lua foo.o

Здесь важно имя файла .lua, поскольку оно определяет, как позднее использовать этот модуль в коде Lua. Имя файла foo.o не имеет значения, за исключением расширения файла .o (по нему luajit определяет используемый формат вывода). Чтобы удалить отладочную информацию Lua из результирующего байт-кода, вместо -bg можно указать приведённый выше параметр -b.

Затем при сборке Nginx или OpenResty передайте параметр --with-ld-opt="foo.o" скрипту ./configure:

./configure --with-ld-opt="/path/to/foo.o" ...

Наконец, в любом коде Lua, выполняемом ngx_lua, можно просто написать:

local foo = require "foo"
foo.go()

Теперь этот фрагмент кода больше не зависит от внешнего файла foo.lua, поскольку он уже скомпилирован в исполняемый файл nginx.

Если при вызове require вы хотите использовать точку в имени модуля Lua, например:

local foo = require "resty.foo"

перед компиляцией в файл .o с помощью утилиты командной строки luajit необходимо переименовать файл foo.lua в resty_foo.lua.

При компиляции файлов .lua в файлы .o важно использовать точно ту же версию LuaJIT, что и при сборке nginx + ngx_lua. Это связано с тем, что формат байт-кода LuaJIT может быть несовместим между разными версиями LuaJIT. При несовместимости формата байт-кода возникнет ошибка Lua во время выполнения с сообщением о том, что модуль Lua не найден.

Если требуется скомпилировать и скомпоновать несколько файлов .lua, укажите соответствующие файлы .o одновременно в значении параметра --with-ld-opt. Например:

./configure --with-ld-opt="/path/to/foo.o /path/to/bar.o" ...

Если файлов .o слишком много, перечислить их все в одной команде может быть неудобно. В этом случае можно создать статическую библиотеку (или архив) для файлов .o, например:

ar rcus libmyluafiles.a *.o

Затем можно скомпоновать архив myluafiles целиком с исполняемым файлом nginx:

./configure \
    --with-ld-opt="-L/path/to/lib -Wl,--whole-archive -lmyluafiles -Wl,--no-whole-archive"

где /path/to/lib — путь к каталогу, содержащему файл libmyluafiles.a. Обратите внимание, что здесь требуется параметр компоновщика --whole-archive, иначе наш архив будет пропущен, поскольку на его символы нет ссылок в основной части исполняемого файла nginx.

Совместное использование данных в рамках рабочего процесса Nginx

Чтобы совместно использовать данные между всеми запросами, обрабатываемыми одним и тем же рабочим процессом Nginx, поместите общие данные в модуль Lua, импортируйте этот модуль с помощью встроенной функции Lua require и затем работайте с общими данными в Lua. Это работает, поскольку каждый модуль Lua загружается только один раз, а все корутины совместно используют один и тот же экземпляр модуля (как его код, так и данные).

Обратите внимание, что настоятельно не рекомендуется использовать глобальные переменные Lua, поскольку это может привести к непредвиденным состояниям гонки между параллельными запросами.

Ниже приведён небольшой пример совместного использования данных в рамках рабочего процесса Nginx через модуль Lua:

-- mydata.lua
local _M = {}

local data = {
    dog = 3,
    cat = 4,
    pig = 5,
}

function _M.get_age(name)
    return data[name]
end

return _M

а затем обращения к ним из nginx.conf:

location /lua {
    content_by_lua_block {
        local mydata = require "mydata"
        ngx.say(mydata.get_age("dog"))
    }
}

Модуль mydata в этом примере будет загружен и выполнен только при первом запросе к локации /lua. Все последующие запросы в том же рабочем процессе Nginx также будут использовать перезагруженный экземпляр модуля и ту же копию содержащихся в нём данных, пока процессу master Nginx не будет отправлен сигнал HUP для принудительной перезагрузки. Этот способ совместного использования данных необходим для высокопроизводительных приложений Lua на основе данного модуля.

Обратите внимание, что данные совместно используются в рамках одного рабочего процесса, а не в рамках всего сервера. То есть, если под управлением master-процесса Nginx работает несколько рабочих процессов, данные между ними не могут передаваться через границы процессов.

Обычно рекомендуется таким образом совместно использовать данные только для чтения. Также можно совместно использовать изменяемые данные между всеми параллельными запросами каждого рабочего процесса Nginx, если в процессе вычислений нет неблокирующих операций ввода-вывода (включая ngx.sleep). Пока вы не передаёте управление обратно циклу обработки событий Nginx и планировщику лёгких потоков ngx_lua (даже неявно), состояние гонки возникнуть не может. Поэтому всегда проявляйте особую осторожность при совместном использовании изменяемых данных на уровне рабочего процесса. Ошибочные оптимизации могут легко привести к состояниям гонки, которые трудно отлаживать под нагрузкой.

Если необходимо совместно использовать данные на уровне всего сервера, используйте один или несколько следующих подходов:

  1. Используйте API ngx.shared.DICT, предоставляемый этим модулем.
  2. Используйте только один рабочий процесс Nginx и один сервер (однако это не рекомендуется для компьютеров с многоядерным процессором или несколькими процессорами).
  3. Используйте механизмы хранения данных, такие как memcached, redis, MySQL или PostgreSQL. Официальные выпуски OpenResty включают набор дополнительных модулей Nginx и библиотек Lua, предоставляющих интерфейсы для работы с этими механизмами хранения данных.

Известные проблемы

Проблемы с подключением TCP-сокета

Метод tcpsock:connect может сообщить success, несмотря на сбой соединения, например из-за ошибок Connection Refused.

Однако последующие попытки работы с объектом cosocket завершатся неудачно и вернут фактическое сообщение об ошибке, вызванной неудачной попыткой подключения.

Эта проблема связана с ограничениями событийной модели Nginx и, по всей видимости, возникает только в Mac OS X.

Приостановка и возобновление корутин Lua

  • Поскольку встроенные функции Lua dofile и require в LuaJIT 2.0/2.1 сейчас реализованы как функции C, если файл Lua, загружаемый с помощью dofile или require, вызывает ngx.location.capture*, ngx.exec, ngx.exit или другие функции API, требующие приостановки, в глобальной области файла Lua, будет вызвана ошибка Lua «attempt to yield across C-call boundary». Чтобы избежать этого, поместите такие вызовы, требующие приостановки, в собственные функции Lua внутри файла, а не в его глобальную область.

Область видимости переменных Lua

При импорте модулей нужно соблюдать осторожность. Следует использовать такой вариант:

local xxx = require('xxx')

а не устаревший вариант:

require('xxx')

Причина в следующем: по замыслу глобальное окружение существует столько же, сколько и связанный с ним обработчик запроса Nginx. У каждого обработчика запроса есть собственный набор глобальных переменных Lua — в этом и заключается изоляция запросов. Модуль Lua фактически загружается первым обработчиком запроса Nginx и кэшируется встроенной функцией require() в таблице package.loaded для последующего использования. Встроенная функция module(), применяемая некоторыми модулями Lua, имеет побочный эффект: она задаёт глобальную переменную, ссылающуюся на таблицу загруженного модуля. Однако эта глобальная переменная очищается в конце обработчика запроса, и у каждого последующего обработчика запроса будет собственное (чистое) глобальное окружение. Поэтому при обращении к значению nil возникнет исключение Lua.

В контексте ngx_lua обычно не рекомендуется использовать глобальные переменные Lua, поскольку:

  1. неправильное использование глобальных переменных Lua отрицательно сказывается на параллельных запросах, если такие переменные должны быть локальными;
  2. для доступа к глобальным переменным Lua требуется поиск в таблице глобального окружения, что требует значительных вычислительных затрат;
  3. в ссылках на некоторые глобальные переменные Lua могут быть опечатки, которые затрудняют отладку.

Поэтому настоятельно рекомендуется всегда объявлять такие переменные в подходящей локальной области видимости.

-- Avoid
foo = 123
-- Recommended
local foo = 123

-- Avoid
function foo() return 123 end
-- Recommended
local function foo() return 123 end

Чтобы найти все случаи использования глобальных переменных Lua в своём коде, запустите инструмент lua-releng для всех исходных файлов .lua:

$ lua-releng
Checking use of Lua global variables in file lib/foo/bar.lua ...
        1       [1489]  SETGLOBAL       7 -1    ; contains
        55      [1506]  GETGLOBAL       7 -3    ; setvar
        3       [1545]  GETGLOBAL       3 -4    ; varexpand

В выводе указано, что строка 1489 файла lib/foo/bar.lua записывает значение в глобальную переменную с именем contains, строка 1506 читает значение глобальной переменной setvar, а строка 1545 читает значение глобальной переменной varexpand.

Этот инструмент проверяет, что все локальные переменные в функциях модуля Lua объявлены с помощью ключевого слова local; в противном случае будет вызвано исключение во время выполнения. Это позволяет избежать нежелательных состояний гонки при обращении к таким переменным. Причины этого описаны в разделе «Совместное использование данных в рамках рабочего процесса Nginx».

Локации, настроенные директивами подзапросов других модулей

Директивы ngx.location.capture и ngx.location.capture_multi не могут перехватывать локации, содержащие директивы add_before_body, add_after_body, auth_request, echo_location, echo_location_async, echo_subrequest или echo_subrequest_async.

location /foo {
    content_by_lua_block {
        res = ngx.location.capture("/bar")
    }
}
location /bar {
    echo_location /blah;
}
location /blah {
    echo "Success!";
}
$ curl -i http://example.com/foo

не будет работать ожидаемым образом.

Косокеты доступны не везде

Из-за внутренних ограничений ядра Nginx API косокетов отключён в следующих контекстах: set_by_lua*, log_by_lua*, header_filter_by_lua* и body_filter_by_lua.

В настоящее время косокеты также отключены в контекстах директив init_by_lua* и init_worker_by_lua*, но в будущем мы можем добавить поддержку этих контекстов, поскольку ограничений в ядре Nginx нет (или их можно обойти).

Однако существует обходной путь, если исходному контексту не нужно ждать результатов работы косокета. Для этого следует создать таймер с нулевой задержкой с помощью API ngx.timer.at и получить результаты работы косокета в обработчике таймера, который выполняется асинхронно относительно исходного контекста, создавшего таймер.

Специальные последовательности экранирования

ПРИМЕЧАНИЕ После выпуска v0.9.17 этой проблемы можно избежать, используя директивы конфигурации *_by_lua_block {}.

Последовательности PCRE, такие как \d, \s или \w, требуют особого внимания, поскольку в строковых литералах символ обратной косой черты, \, удаляется и парсером языка Lua, и парсером конфигурационного файла Nginx перед обработкой, если он не находится внутри директивы *_by_lua_block {}. Поэтому следующий фрагмент не будет работать ожидаемым образом:

# nginx.conf
? location /test {
?     content_by_lua '
?         local regex = "\d+"  -- THIS IS WRONG OUTSIDE OF A *_by_lua_block DIRECTIVE
?         local m = ngx.re.match("hello, 1234", regex)
?         if m then ngx.say(m[0]) else ngx.say("not matched!") end
?     ';
? }
# evaluates to "not matched!"

Чтобы этого избежать, экранируйте обратную косую черту дважды:

# nginx.conf
location /test {
    content_by_lua '
        local regex = "\\\\d+"
        local m = ngx.re.match("hello, 1234", regex)
        if m then ngx.say(m[0]) else ngx.say("not matched!") end
    ';
}
# evaluates to "1234"

Здесь \\\\d+ преобразуется парсером конфигурационного файла Nginx в \\d+, а затем парсер языка Lua перед выполнением преобразует это в \d+.

Также шаблон регулярного выражения можно представить в виде строкового литерала Lua в длинных скобках, заключив его в «длинные скобки» [[...]]. В этом случае обратную косую черту достаточно экранировать только один раз для парсера конфигурационного файла Nginx.

# nginx.conf
location /test {
    content_by_lua '
        local regex = [[\\d+]]
        local m = ngx.re.match("hello, 1234", regex)
        if m then ngx.say(m[0]) else ngx.say("not matched!") end
    ';
}
# evaluates to "1234"

Здесь [[\\d+]] преобразуется парсером конфигурационного файла Nginx в [[\d+]], и это обрабатывается корректно.

Обратите внимание, что может потребоваться более длинная форма длинных скобок, [=[...]=], если шаблон регулярного выражения содержит последовательности [...]. При желании в качестве формы по умолчанию можно использовать вариант [=[...]=].

# nginx.conf
location /test {
    content_by_lua '
        local regex = [=[[0-9]+]=]
        local m = ngx.re.match("hello, 1234", regex)
        if m then ngx.say(m[0]) else ngx.say("not matched!") end
    ';
}
# evaluates to "1234"

Ещё один способ экранировать последовательности PCRE — размещать код Lua во внешних файлах сценариев и выполнять его с помощью различных директив *_by_lua_file. В этом случае обратные косые черты удаляются только парсером языка Lua, поэтому каждую из них достаточно экранировать один раз.

-- test.lua
local regex = "\\d+"
local m = ngx.re.match("hello, 1234", regex)
if m then ngx.say(m[0]) else ngx.say("not matched!") end
-- evaluates to "1234"

Во внешних файлах сценариев последовательности PCRE, представленные в виде строковых литералов Lua в длинных скобках, не требуют изменений.

-- test.lua
local regex = [[\d+]]
local m = ngx.re.match("hello, 1234", regex)
if m then ngx.say(m[0]) else ngx.say("not matched!") end
-- evaluates to "1234"

Как отмечалось ранее, последовательности PCRE внутри директив *_by_lua_block {} (доступных начиная с выпуска v0.9.17) не требуют изменений.

# nginx.conf
location /test {
    content_by_lua_block {
        local regex = [[\d+]]
        local m = ngx.re.match("hello, 1234", regex)
        if m then ngx.say(m[0]) else ngx.say("not matched!") end
    }
}
# evaluates to "1234"

ПРИМЕЧАНИЕ Если код Lua очень длинный, рекомендуется использовать by_lua_file.

Совместное использование с SSI не поддерживается

Совместное использование SSI и ngx_lua в одном запросе Nginx вообще не поддерживается. Используйте только ngx_lua. Всё, что можно сделать с помощью SSI, можно сделать и средствами ngx_lua, причём использование ngx_lua может быть эффективнее.

Режим SPDY поддерживается не полностью

Некоторые API Lua, предоставляемые ngx_lua, пока не работают в режиме SPDY Nginx: ngx.location.capture, ngx.location.capture_multi и ngx.req.socket.

Отсутствие данных при досрочно завершённых запросах

Nginx может досрочно завершить запрос, как минимум, с одним из следующих кодов:

  • 400 (Неверный запрос)
  • 405 (Метод не разрешён)
  • 408 (Время ожидания запроса истекло)
  • 413 (Тело запроса слишком велико)
  • 414 (URI запроса слишком длинный)
  • 494 (Заголовки запроса слишком велики)
  • 499 (Клиент закрыл запрос)
  • 500 (Внутренняя ошибка сервера)
  • 501 (Не реализовано)

Это означает, что обычные фазы, например rewrite или access, пропускаются. Кроме того, последующие фазы, которые выполняются в любом случае, например log_by_lua, не будут иметь доступа к информации, обычно задаваемой в этих фазах.

ПЛАНЫ

  • cosocket: реализовать неподключённый UDP API LuaSocket.
  • cosocket: добавить поддержку в контексте init_by_lua*.
  • cosocket: проверить и объединить исправление aviramc, добавляющее метод bsdrecv.
  • cosocket: добавить параметры конфигурации для различных стратегий обработки превышения лимита подключений косокетов в пулах.
  • использовать ngx_hash_t для оптимизации встроенного поиска заголовков, применяемого в ngx.req.set_header и т. д.
  • добавить параметры ignore_resp_headers, ignore_resp_body и ignore_resp для методов ngx.location.capture и ngx.location.capture_multi, чтобы пользователь мог выполнять микротонкую настройку производительности.
  • добавить поддержку автоматического разделения времени выполнения кода Lua на интервалы: активно приостанавливать и возобновлять виртуальную машину Lua с помощью отладочных хуков Lua.
  • добавить режим stat, аналогичный mod_lua.

Изменения

Изменения в каждом выпуске этого модуля перечислены в журналах изменений пакета OpenResty:

https://openresty.org/#Changes

Набор тестов

Для запуска набора тестов требуются следующие зависимости:

  • Nginx версии >= 1.4.2

  • Модули Perl:

    • Test::Nginx: https://github.com/openresty/test-nginx
  • Модули Nginx:

    • ngx_devel_kit
    • ngx_set_misc
    • ngx_auth_request (не требуется, если вы используете Nginx 1.5.4+.
    • ngx_echo
    • ngx_memc
    • ngx_srcache
    • ngx_lua (то есть этот модуль)
    • ngx_lua_upstream
    • ngx_headers_more
    • ngx_drizzle
    • ngx_rds_json
    • ngx_coolkit
    • ngx_redis2

Порядок добавления этих модулей при конфигурировании важен, поскольку, например, положение любого модуля фильтра в цепочке фильтров определяет итоговый вывод. Правильный порядок добавления показан выше.

  • Сторонние библиотеки Lua:

    • lua-cjson
  • Приложения:

    • mysql: создать базу данных 'ngx_test', предоставить все привилегии пользователю 'ngx_test', пароль — 'ngx_test'
    • memcached: прослушивает порт по умолчанию, 11211.
    • redis: прослушивает порт по умолчанию, 6379.

Дополнительные сведения о настройке среды тестирования см. также в сценарии сборки для разработчиков.

Чтобы запустить весь набор тестов в режиме тестирования по умолчанию:

cd /path/to/lua-nginx-module
export PATH=/path/to/your/nginx/sbin:$PATH
prove -I/path/to/test-nginx/lib -r t

Чтобы запустить определённые файлы тестов:

cd /path/to/lua-nginx-module
export PATH=/path/to/your/nginx/sbin:$PATH
prove -I/path/to/test-nginx/lib t/002-content.t t/003-errors.t

Чтобы запустить определённый блок тестов в конкретном файле тестов, добавьте строку --- ONLY в нужный блок тестов, а затем используйте утилиту prove для запуска этого файла .t.

Также доступны различные режимы тестирования на основе mockeagain, valgrind и т. д. Дополнительные сведения о расширенных режимах тестирования см. в документации Test::Nginx. См. также отчёты о тестировании кластера Nginx, работающего на Amazon EC2: https://qa.openresty.org.

Авторские права и лицензия

Этот модуль распространяется по лицензии BSD.

Copyright (C) 2009-2017, автор Xiaozhe Wang (chaoslawful) chaoslawful@gmail.com.

Copyright (C) 2009-2019, автор Yichun "agentzh" Zhang (章亦春) agentzh@gmail.com, OpenResty Inc.

Все права защищены.

Разрешается распространение и использование в исходной и двоичной формах, с изменениями или без них, при соблюдении следующих условий:

  • При распространении исходного кода необходимо сохранить приведённое выше уведомление об авторских правах, этот список условий и следующий отказ от гарантий.

  • При распространении в двоичной форме необходимо воспроизвести приведённое выше уведомление об авторских правах, этот список условий и следующий отказ от гарантий в документации и/или других материалах, предоставляемых вместе с распространением.

ДАННОЕ ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ ПРЕДОСТАВЛЯЕТСЯ ВЛАДЕЛЬЦАМИ АВТОРСКИХ ПРАВ И УЧАСТНИКАМИ «КАК ЕСТЬ»; ПРИ ЭТОМ ОТКАЗЫВАЮТСЯ ОТ ЛЮБЫХ ЯВНЫХ ИЛИ ПОДРАЗУМЕВАЕМЫХ ГАРАНТИЙ, ВКЛЮЧАЯ, ПОМИМО ПРОЧЕГО, ПОДРАЗУМЕВАЕМЫЕ ГАРАНТИИ ТОВАРНОЙ ПРИГОДНОСТИ И ПРИГОДНОСТИ ДЛЯ КОНКРЕТНОЙ ЦЕЛИ. НИ ПРИ КАКИХ ОБСТОЯТЕЛЬСТВАХ ВЛАДЕЛЕЦ АВТОРСКИХ ПРАВ ИЛИ УЧАСТНИКИ НЕ НЕСУТ ОТВЕТСТВЕННОСТИ ЗА ЛЮБОЙ ПРЯМОЙ, КОСВЕННЫЙ, СЛУЧАЙНЫЙ, ОСОБЫЙ, ШТРАФНОЙ ИЛИ ПОСЛЕДУЮЩИЙ УЩЕРБ (ВКЛЮЧАЯ, ПОМИМО ПРОЧЕГО, ПРИОБРЕТЕНИЕ ЗАМЕНЯЮЩИХ ТОВАРОВ ИЛИ УСЛУГ, ПОТЕРЮ ВОЗМОЖНОСТИ ИСПОЛЬЗОВАНИЯ, ДАННЫХ ИЛИ ПРИБЫЛИ, А ТАКЖЕ ПЕРЕРЫВ В ДЕЯТЕЛЬНОСТИ), ВОЗНИКШИЙ КАКИМ-ЛИБО ОБРАЗОМ И ПО ЛЮБОЙ ТЕОРИИ ОТВЕТСТВЕННОСТИ — ДОГОВОРНОЙ, СТРОГОЙ ИЛИ ДЕЛИКТНОЙ (ВКЛЮЧАЯ НЕБРЕЖНОСТЬ И ИНОЕ), — В РЕЗУЛЬТАТЕ ИСПОЛЬЗОВАНИЯ ДАННОГО ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ, ДАЖЕ ЕСЛИ О ВОЗМОЖНОСТИ ТАКОГО УЩЕРБА БЫЛО СООБЩЕНО.

См. также

Публикации в блоге:

  • Введение в пламенные графики загрузки ЦП в Lua
  • Как OpenResty и Nginx выделяют память и управляют ею
  • Как разделяемая память OpenResty и Nginx потребляет ОЗУ
  • Фрагментация памяти в зонах разделяемой памяти OpenResty и Nginx

Другие связанные модули и библиотеки:

  • ngx_stream_lua_module — официальный порт этого модуля для подсистемы Nginx «stream» (для универсального взаимодействия с нижестоящими узлами по TCP).
  • Библиотека lua-resty-memcached, основанная на косокетах ngx_lua.
  • Библиотека lua-resty-redis, основанная на косокетах ngx_lua.
  • Библиотека lua-resty-mysql, основанная на косокетах ngx_lua.
  • Библиотека lua-resty-upload, основанная на косокетах ngx_lua.
  • Библиотека lua-resty-dns, основанная на косокетах ngx_lua.
  • Библиотека lua-resty-websocket для серверов и клиентов WebSocket, основанная на косокетах ngx_lua.
  • Библиотека lua-resty-string, основанная на LuaJIT FFI.
  • Библиотека lua-resty-lock для простого неблокирующего API блокировок.
  • Библиотека lua-resty-cookie для работы с HTTP-файлами cookie.
  • Маршрутизация запросов к различным запросам MySQL на основе аргументов URI
  • Динамическая маршрутизация на основе Redis и Lua
  • Использование LuaRocks с ngx_lua
  • Введение в ngx_lua
  • ngx_devel_kit
  • echo-nginx-module
  • drizzle-nginx-module
  • postgres-nginx-module
  • memc-nginx-module
  • Пакет OpenResty
  • Набор инструментов Nginx Systemtap

Директивы

  • lua_load_resty_core
  • lua_capture_error_log
  • lua_use_default_type
  • lua_malloc_trim
  • lua_code_cache
  • lua_thread_cache_max_entries
  • lua_regex_cache_max_entries
  • lua_regex_match_limit
  • lua_package_path
  • lua_package_cpath
  • init_by_lua
  • init_by_lua_block
  • init_by_lua_file
  • init_worker_by_lua
  • init_worker_by_lua_block
  • init_worker_by_lua_file
  • exit_worker_by_lua_block
  • exit_worker_by_lua_file
  • set_by_lua
  • set_by_lua_block
  • set_by_lua_file
  • content_by_lua
  • content_by_lua_block
  • content_by_lua_file
  • server_rewrite_by_lua_block
  • server_rewrite_by_lua_file
  • rewrite_by_lua
  • rewrite_by_lua_block
  • rewrite_by_lua_file
  • access_by_lua
  • access_by_lua_block
  • access_by_lua_file
  • header_filter_by_lua
  • header_filter_by_lua_block
  • header_filter_by_lua_file
  • body_filter_by_lua
  • body_filter_by_lua_block
  • body_filter_by_lua_file
  • log_by_lua
  • log_by_lua_block
  • log_by_lua_file
  • balancer_by_lua_block
  • balancer_by_lua_file
  • balancer_keepalive
  • lua_need_request_body
  • ssl_client_hello_by_lua_block
  • ssl_client_hello_by_lua_file
  • ssl_certificate_by_lua_block
  • ssl_certificate_by_lua_file
  • ssl_session_fetch_by_lua_block
  • ssl_session_fetch_by_lua_file
  • ssl_session_store_by_lua_block
  • ssl_session_store_by_lua_file
  • lua_shared_dict
  • lua_socket_connect_timeout
  • lua_socket_send_timeout
  • lua_socket_send_lowat
  • lua_socket_read_timeout
  • lua_socket_buffer_size
  • lua_socket_pool_size
  • lua_socket_keepalive_timeout
  • lua_socket_log_errors
  • lua_ssl_ciphers
  • lua_ssl_crl
  • lua_ssl_protocols
  • lua_ssl_certificate
  • lua_ssl_certificate_key
  • lua_ssl_trusted_certificate
  • lua_ssl_verify_depth
  • lua_ssl_conf_command
  • lua_http10_buffering
  • rewrite_by_lua_no_postpone
  • access_by_lua_no_postpone
  • lua_transform_underscores_in_response_headers
  • lua_check_client_abort
  • lua_max_pending_timers
  • lua_max_running_timers
  • lua_sa_restart
  • lua_worker_thread_vm_pool_size

Основными строительными блоками для написания сценариев Nginx на Lua являются директивы. С помощью директив указывают, когда выполняется пользовательский код Lua и как используются результаты. Ниже приведена схема порядка выполнения директив.

Lua Nginx Modules Directives

lua_load_resty_core

синтаксис: lua_load_resty_core on|off

значение по умолчанию: lua_load_resty_core on

контекст: http

Эта директива устарела начиная с выпуска v0.10.16 данного модуля. Модуль resty.core из lua-resty-core теперь обязательно загружается при инициализации виртуальной машины Lua. Указание этой директивы не оказывает никакого эффекта.

Эта директива впервые появилась в выпуске v0.10.15 и использовалась для необязательной загрузки модуля resty.core.

lua_capture_error_log

синтаксис: lua_capture_error_log size

значение по умолчанию: none

контекст: http

Включает буфер указанного size размера для перехвата всех сообщений журнала ошибок Nginx (не только сообщений, созданных этим модулем или подсистемой HTTP Nginx, а вообще всех), без обращения к файлам или дискам.

В значении size можно использовать единицы измерения, например k и m:

lua_capture_error_log 100k;

Как правило, буфер размером 4 КБ может вместить около 20 типичных сообщений журнала ошибок. Учитывайте это при настройке!

Размер этого буфера никогда не увеличивается. Если он заполнен, новые сообщения журнала ошибок заменяют самые старые сообщения в буфере.

Размер буфера должен превышать максимальную длину одного сообщения журнала ошибок (4 КБ в OpenResty и 2 КБ в стандартном NGINX).

Сообщения из буфера можно прочитать в Lua с помощью функции get_logs() модуля ngx.errlog библиотеки lua-resty-core. Эта функция API Lua возвращает перехваченные сообщения журнала ошибок и удаляет уже прочитанные сообщения из глобального буфера перехвата, освобождая место для новых данных журнала ошибок. Поэтому не следует настраивать слишком большой буфер, если пользователь достаточно быстро считывает буферизованные данные журнала ошибок.

Обратите внимание, что уровень журналирования, заданный стандартной директивой error_log, влияет на перехват сообщений. Перехватываются только сообщения с уровнем не ниже уровня, указанного в директиве error_log. Пользователь по-прежнему может динамически задать ещё более высокий уровень фильтрации с помощью функции API Lua errlog.set_filter_level. Таким образом, этот механизм гибче статической директивы error_log.

Следует отметить, что перехватить отладочные журналы невозможно без сборки OpenResty или Nginx с параметром ./configure --with-debug. Включать отладочные журналы в производственных сборках настоятельно не рекомендуется из-за высоких накладных расходов.

Эта директива впервые появилась в выпуске v0.10.9.

lua_use_default_type

синтаксис: lua_use_default_type on | off

значение по умолчанию: lua_use_default_type on

контекст: http, server, location, location if

Указывает, следует ли использовать MIME-тип, заданный директивой default_type, в качестве значения по умолчанию для заголовка ответа Content-Type. Отключите эту директиву, если заголовок ответа Content-Type по умолчанию для обработчиков запросов Lua не нужен.

По умолчанию эта директива включена.

Эта директива впервые появилась в выпуске v0.9.1.

lua_malloc_trim

синтаксис: lua_malloc_trim <request-count>

значение по умолчанию: lua_malloc_trim 1000

контекст: http

Предписывает базовой библиотеке среды выполнения libc освобождать обратно операционной системе кэшированную свободную память после обработки ядром Nginx каждых N запросов. По умолчанию N равно 1000. Количество запросов можно настроить, задав собственное значение. Меньшие значения означают более частое освобождение памяти, что может увеличить нагрузку на ЦП и уменьшить объём используемой памяти; большие значения обычно снижают нагрузку на ЦП, но увеличивают объём используемой памяти. Подберите значение для своего случая.

Если задать аргументу значение 0, периодическая очистка памяти будет полностью отключена.

lua_malloc_trim 0;  # turn off trimming completely

В текущей реализации для подсчёта запросов используется обработчик фазы журналирования Nginx. Поэтому директивы log_subrequest on в nginx.conf могут ускорить подсчёт при наличии подзапросов. По умолчанию учитываются только «основные запросы».

Обратите внимание, что эта директива не влияет на память, выделенную собственным аллокатором LuaJIT с помощью системного вызова mmap.

Эта директива впервые появилась в выпуске v0.10.7.

lua_code_cache

синтаксис: lua_code_cache on | off

значение по умолчанию: lua_code_cache on

контекст: http, server, location, location if

Включает или отключает кэш кода Lua для кода Lua в директивах *_by_lua_file (например, set_by_lua_file и content_by_lua_file) и для модулей Lua.

При отключении этой директивы каждый запрос, обслуживаемый ngx_lua, выполняется в отдельном экземпляре виртуальной машины Lua, начиная с выпуска 0.9.3. Поэтому файлы Lua, указанные в set_by_lua_file, content_by_lua_file, access_by_lua_file и других директивах, не будут кэшироваться, а все используемые модули Lua будут загружаться заново. Это позволяет разработчикам применять подход «редактирование и обновление».

Однако обратите внимание, что код Lua, встроенный непосредственно в nginx.conf, например код, указанный в директивах set_by_lua, content_by_lua, access_by_lua и rewrite_by_lua, не обновится при редактировании встроенного кода Lua в файле nginx.conf, поскольку корректно разобрать файл nginx.conf может только парсер конфигурационного файла Nginx. Единственный способ применить изменения — перезагрузить конфигурационный файл, отправив сигнал HUP, или просто перезапустить Nginx.

Даже если кэш кода включён, файлы Lua, загружаемые с помощью dofile или loadfile в *_by_lua_file, кэшировать нельзя (если только вы не кэшируете результаты самостоятельно). Обычно можно использовать директивы init_by_lua или init_by_lua_file, чтобы загрузить все такие файлы, либо просто сделать эти файлы Lua полноценными модулями Lua и загружать их с помощью require.

Модуль ngx_lua пока не поддерживает режим stat, доступный в модуле Apache mod_lua.

Отключать кэш кода Lua в рабочей среде настоятельно не рекомендуется; это следует делать только во время разработки, поскольку это значительно снижает общую производительность. Например, после отключения кэша кода Lua производительность примера Lua «hello world» может упасть на порядок.

lua_thread_cache_max_entries

синтаксис: lua_thread_cache_max_entries <num>

значение по умолчанию: lua_thread_cache_max_entries 1024

контекст: http

Задаёт максимальное количество записей, допустимое в кэше объектов потоков Lua на уровне рабочего процесса.

Этот кэш повторно использует объекты сборщика мусора потоков Lua во всех наших «лёгких потоках».

Нулевое значение <num> отключает кэш.

Обратите внимание: для этой возможности требуется LuaJIT от OpenResty с новым C API lua_resetthread.

Эта возможность впервые появилась в версии v0.10.9.

lua_regex_cache_max_entries

синтаксис: lua_regex_cache_max_entries <num>

значение по умолчанию: lua_regex_cache_max_entries 1024

контекст: http

Задаёт максимальное количество записей, допустимое в кэше скомпилированных регулярных выражений на уровне рабочего процесса.

Регулярные выражения, используемые в ngx.re.match, ngx.re.gmatch, ngx.re.sub и ngx.re.gsub, будут кэшироваться здесь, если указан параметр регулярного выражения o (то есть флаг однократной компиляции).

По умолчанию допускается 1024 записи. При достижении этого предела новые регулярные выражения кэшироваться не будут (как если бы параметр o не был указан), и в файл error.log будет выведено ровно одно предупреждение:

2011/08/27 23:18:26 [warn] 31997#0: *1 lua exceeding regex cache max entries (1024), ...

Если вы используете реализацию ngx.re.* из lua-resty-core, загрузив модуль resty.core.regex (или только модуль resty.core), для используемого здесь кэша регулярных выражений применяется кэш LRU.

Не включайте параметр o для регулярных выражений (и/или аргументы строк replace для ngx.re.sub и ngx.re.gsub), которые создаются на лету и могут принимать бесконечное множество вариантов, чтобы не достичь заданного предела.

lua_regex_match_limit

синтаксис: lua_regex_match_limit <num>

значение по умолчанию: lua_regex_match_limit 0

контекст: http

Задаёт «предел сопоставления», используемый библиотекой PCRE при выполнении API ngx.re. Цитируя справочную страницу PCRE: «предел ... ограничивает объём возможного возврата с проверкой вариантов».

При достижении предела функции API ngx.re возвращают на стороне Lua строку ошибки «pcre_exec() failed: -8».

Если задать предел равным 0, будет использоваться стандартный «предел сопоставления», применяемый при компиляции библиотеки PCRE. Это значение по умолчанию для данной директивы.

Эта директива впервые появилась в выпуске v0.8.5.

lua_package_path

синтаксис: lua_package_path <lua-style-path-str>

значение по умолчанию: Содержимое переменной среды LUA_PATH или значения по умолчанию, встроенные при компиляции Lua.

контекст: http

Задаёт путь поиска модулей Lua, используемый скриптами, указанными в set_by_lua, content_by_lua и других директивах. Строка пути имеет стандартный для Lua формат, а ;; можно использовать вместо исходных путей поиска.

Начиная с выпуска v0.5.0rc29 в строке пути поиска можно использовать специальную запись $prefix или ${prefix}, чтобы указать путь к server prefix, который обычно определяется параметром командной строки -p PATH при запуске сервера Nginx.

lua_package_cpath

синтаксис: lua_package_cpath <lua-style-cpath-str>

значение по умолчанию: Содержимое переменной среды LUA_CPATH или значения по умолчанию, встроенные при компиляции Lua.

контекст: http

Задаёт путь поиска C-модулей Lua, используемый скриптами, указанными в set_by_lua, content_by_lua и других директивах. Строка cpath имеет стандартный для Lua формат, а ;; можно использовать вместо исходного cpath.

Начиная с выпуска v0.5.0rc29 в строке пути поиска можно использовать специальную запись $prefix или ${prefix}, чтобы указать путь к server prefix, который обычно определяется параметром командной строки -p PATH при запуске сервера Nginx.

init_by_lua

синтаксис: init_by_lua <lua-script-str>

контекст: http

фаза: loading-config

ПРИМЕЧАНИЕ После выпуска v0.9.17 использовать эту директиву не рекомендуется. Вместо неё используйте директиву init_by_lua_block.

Подобно директиве init_by_lua_block, но принимает исходный код Lua непосредственно в строковом литерале Nginx (что требует экранирования специальных символов).

Например:

init_by_lua '
    print("I need no extra escaping here, for example: \r\nblah")
'

Эта директива впервые появилась в выпуске v0.5.5.

init_by_lua_block

синтаксис: init_by_lua_block { lua-script }

контекст: http

фаза: loading-config

Когда Nginx получает сигнал HUP и начинает перезагружать файл конфигурации, виртуальная машина Lua также создаётся заново, и init_by_lua_block снова выполняется в новой виртуальной машине Lua. Если директива lua_code_cache отключена (по умолчанию она включена), обработчик init_by_lua_block будет выполняться при каждом запросе, поскольку в этом специальном режиме для каждого запроса всегда создаётся отдельная виртуальная машина Lua.

Обычно с помощью этого обработчика можно предварительно загрузить модули Lua при запуске сервера и воспользоваться оптимизацией копирования при записи (COW), поддерживаемой современными операционными системами. Ниже приведён пример предварительной загрузки модулей Lua:

# this runs before forking out nginx worker processes:
init_by_lua_block { require "cjson" }

server {
    location = /api {
        content_by_lua_block {
            -- the following require() will just  return
            -- the already loaded module from package.loaded:
            ngx.say(require "cjson".encode{dog = 5, cat = 6})
        }
    }
}

На этом этапе также можно инициализировать разделяемое хранилище shm директивы lua_shared_dict. Пример:

lua_shared_dict dogs 1m;

init_by_lua_block {
    local dogs = ngx.shared.dogs
    dogs:set("Tom", 56)
}

server {
    location = /api {
        content_by_lua_block {
            local dogs = ngx.shared.dogs
            ngx.say(dogs:get("Tom"))
        }
    }
}

Обратите внимание: разделяемое хранилище shm директивы lua_shared_dict не очищается при перезагрузке конфигурации (например, при получении сигнала HUP). Поэтому, если в этом случае вы не хотите повторно инициализировать хранилище shm в коде init_by_lua_block, достаточно задать пользовательский флаг в хранилище shm и всегда проверять его в коде init_by_lua_block.

Поскольку код Lua в этом контексте выполняется до того, как Nginx создаёт рабочие процессы (если они есть), данные и код, загруженные здесь, будут использовать возможность копирования при записи (COW), предоставляемую многими операционными системами, во всех рабочих процессах, что позволит значительно сэкономить память.

Не инициализируйте собственные глобальные переменные Lua в этом контексте: использование глобальных переменных Lua снижает производительность и может загрязнять глобальное пространство имён (подробности см. в разделе Область видимости переменных Lua). Рекомендуется использовать подходящие файлы модулей Lua (но не используйте стандартную функцию Lua module() для определения модулей Lua, поскольку она также загрязняет глобальное пространство имён) и вызывать require(), чтобы загрузить собственные файлы модулей в init_by_lua_block или других контекстах (require() кэширует загруженные модули Lua в глобальной таблице package.loaded в реестре Lua, поэтому модули загружаются только один раз для всего экземпляра виртуальной машины Lua).

В этом контексте поддерживается лишь небольшой набор API Nginx для Lua:

  • API ведения журнала: ngx.log и print,
  • API общего словаря: ngx.shared.DICT.

В будущем в этом контексте могут появиться и другие API Nginx для Lua по запросам пользователей.

В этом контексте можно безопасно использовать библиотеки Lua, выполняющие блокирующий ввод-вывод, поскольку блокировка главного процесса во время запуска сервера вполне допустима. Даже ядро Nginx выполняет блокирующий ввод-вывод (по крайней мере, при разрешении имён хостов вышестоящих серверов) на этапе загрузки конфигурации.

Внимательно проверяйте свой код Lua, зарегистрированный в этом контексте, на наличие потенциальных уязвимостей, поскольку главный процесс Nginx часто запускается от имени учётной записи root.

Эта директива впервые появилась в выпуске v0.9.17.

Подробнее об OpenResty и зонах разделяемой памяти Nginx см. в следующих публикациях блога:

  • Как зоны разделяемой памяти OpenResty и Nginx используют оперативную память
  • Фрагментация памяти в зонах разделяемой памяти OpenResty и Nginx

init_by_lua_file

синтаксис: init_by_lua_file <path-to-lua-script-file>

контекст: http

фаза: loading-config

Эквивалентна init_by_lua_block, за исключением того, что файл, указанный в <path-to-lua-script-file>, содержит код Lua или байт-код LuaJIT, который будет выполнен.

Если указан относительный путь, например foo/bar.lua, он будет преобразован в абсолютный путь относительно пути server prefix, определяемого параметром командной строки -p PATH при запуске сервера Nginx.

Эта директива впервые появилась в выпуске v0.5.5.

init_worker_by_lua

синтаксис: init_worker_by_lua <lua-script-str>

контекст: http

фаза: starting-worker

ПРИМЕЧАНИЕ После выпуска v0.9.17 использовать эту директиву не рекомендуется. Вместо неё используйте директиву init_worker_by_lua_block.

Подобно директиве init_worker_by_lua_block, но принимает исходный код Lua непосредственно в строковом литерале Nginx (что требует экранирования специальных символов).

Например:

init_worker_by_lua '
    print("I need no extra escaping here, for example: \r\nblah")
';

Эта директива впервые появилась в выпуске v0.9.5.

Начиная с выпуска v0.10.12 этот обработчик больше не выполняется в процессах диспетчера и загрузчика кэша.

init_worker_by_lua_block

синтаксис: init_worker_by_lua_block { lua-script }

контекст: http

фаза: starting-worker

Выполняет указанный код Lua при запуске каждого рабочего процесса Nginx, если главный процесс включён. Если главный процесс отключён, этот обработчик выполняется сразу после init_by_lua*.

Этот обработчик часто используют для создания повторяющихся таймеров для каждого рабочего процесса (с помощью API Lua ngx.timer.at) — например, для проверки работоспособности серверной части или выполнения других периодических задач. Ниже приведён пример:

init_worker_by_lua_block {
    local delay = 3  -- in seconds
    local new_timer = ngx.timer.at
    local log = ngx.log
    local ERR = ngx.ERR
    local check

    check = function(premature)
        if not premature then
            -- do the health check or other routine work
            local ok, err = new_timer(delay, check)
            if not ok then
                log(ERR, "failed to create timer: ", err)
                return
            end
        end

        -- do something in timer
    end

    local hdl, err = new_timer(delay, check)
    if not hdl then
        log(ERR, "failed to create timer: ", err)
        return
    end

    -- other job in init_worker_by_lua
}

Эта директива впервые появилась в выпуске v0.9.17.

Начиная с выпуска v0.10.12 этот обработчик больше не выполняется в процессах диспетчера и загрузчика кэша.

init_worker_by_lua_file

синтаксис: init_worker_by_lua_file <lua-file-path>

контекст: http

фаза: starting-worker

Подобно директиве init_worker_by_lua_block, но принимает путь к файлу с исходным кодом Lua или байт-кодом Lua.

Эта директива впервые появилась в выпуске v0.9.5.

Начиная с выпуска v0.10.12 этот обработчик больше не выполняется в процессах диспетчера и загрузчика кэша.

exit_worker_by_lua_block

синтаксис: exit_worker_by_lua_block { lua-script }

контекст: http

фаза: exiting-worker

Выполняет указанный код Lua при завершении каждого рабочего процесса Nginx, если главный процесс включён. Если главный процесс отключён, этот обработчик выполняется перед завершением процесса Nginx.

Этот обработчик часто используют для освобождения ресурсов, выделенных каждым рабочим процессом (например, ресурсов, выделенных с помощью init_worker_by_lua*), или для предотвращения аварийного завершения рабочих процессов.

Например:

exit_worker_by_lua_block {
    print("log from exit_worker_by_lua_block")
}

Создавать здесь таймеры (даже с нулевой задержкой) нельзя, поскольку этот обработчик выполняется после обработки всех таймеров.

Эта директива впервые появилась в выпуске v0.10.18.

exit_worker_by_lua_file

синтаксис: exit_worker_by_lua_file <path-to-lua-script-file>

контекст: http

фаза: exiting-worker

Подобно директиве exit_worker_by_lua_block, но принимает путь к файлу с исходным кодом Lua или байт-кодом Lua.

Эта директива впервые появилась в выпуске v0.10.18.

set_by_lua

синтаксис: set_by_lua $res <lua-script-str> [$arg1 $arg2 ...]

контекст: server, server if, location, location if

фаза: rewrite

ПРИМЕЧАНИЕ После выпуска v0.9.17 использовать эту директиву не рекомендуется. Вместо неё используйте директиву set_by_lua_block.

Подобно директиве set_by_lua_block, но принимает исходный код Lua непосредственно в строковом литерале Nginx (что требует экранирования специальных символов) и имеет следующие особенности:

  1. Эта директива поддерживает дополнительные аргументы после скрипта Lua.

Например:

set_by_lua $res ' return 32 + math.cos(32) ';
# $res now has the value "32.834223360507" or alike.

Начиная с выпуска v0.5.0rc29 интерполяция переменных Nginx отключена для аргумента <lua-script-str> этой директивы, поэтому символ доллара ($) можно использовать напрямую.

Для этой директивы требуется модуль ngx_devel_kit.

set_by_lua_block

синтаксис: set_by_lua_block $res { lua-script }

контекст: server, server if, location, location if

фаза: rewrite

Выполняет код, указанный в паре фигурных скобок ({}), и возвращает строковый результат в $res. Код в паре фигурных скобок ({}) может вызывать функции API и получать входные аргументы из таблицы ngx.arg (индексация начинается с 1 и далее последовательно увеличивается).

Эта директива предназначена для выполнения коротких и быстрых блоков кода, поскольку на время выполнения кода цикл обработки событий Nginx блокируется. Поэтому следует избегать длительных последовательностей кода.

Эта директива реализована путём добавления пользовательских команд в список команд стандартного модуля ngx_http_rewrite_module. Поскольку ngx_http_rewrite_module не поддерживает неблокирующий ввод-вывод в своих командах, в этой директиве нельзя использовать API Lua, которым требуется приостановить выполнение текущего «лёгкого потока» Lua.

В частности, в контексте set_by_lua_block сейчас отключены следующие функции API:

  • Функции API вывода (например, ngx.say и ngx.send_headers)
  • Функции API управления (например, ngx.exit)
  • Функции API подзапросов (например, ngx.location.capture и ngx.location.capture_multi)
  • Функции API cosocket (например, ngx.socket.tcp и ngx.req.socket).
  • Функция API приостановки ngx.sleep.

Кроме того, обратите внимание: эта директива может одновременно записывать значение только в одну переменную Nginx. Однако эту проблему можно обойти с помощью интерфейса ngx.var.VARIABLE.

location /foo {
    set $diff ''; # we have to predefine the $diff variable here

    set_by_lua_block $sum {
        local a = 32
        local b = 56

        ngx.var.diff = a - b  -- write to $diff directly
        return a + b          -- return the $sum value normally
    }

    echo "sum = $sum, diff = $diff";
}

Эту директиву можно свободно комбинировать со всеми директивами модулей ngx_http_rewrite_module, set-misc-nginx-module и array-var-nginx-module. Все эти директивы выполняются в том же порядке, в котором они указаны в файле конфигурации.

set $foo 32;
set_by_lua_block $bar { return tonumber(ngx.var.foo) + 1 }
set $baz "bar: $bar";  # $baz == "bar: 33"

Дополнительное экранирование в блоке кода Lua не требуется.

Для этой директивы требуется модуль ngx_devel_kit.

Эта директива впервые появилась в выпуске v0.9.17.

set_by_lua_file

синтаксис: set_by_lua_file $res <path-to-lua-script-file> [$arg1 $arg2 ...]

контекст: server, server if, location, location if

фаза: rewrite

Эквивалентна set_by_lua_block, за исключением того, что файл, указанный в <path-to-lua-script-file>, содержит код Lua или, начиная с выпуска v0.5.0rc32, байт-код LuaJIT, который будет выполнен.

В строке аргумента <path-to-lua-script-file> этой директивы поддерживается интерполяция переменных Nginx. Однако следует принять особые меры предосторожности против атак с внедрением кода.

Если указан относительный путь, например foo/bar.lua, он будет преобразован в абсолютный путь относительно пути server prefix, определяемого параметром командной строки -p PATH при запуске сервера Nginx.

Если кэш кода Lua включён (по умолчанию), пользовательский код загружается при первом запросе, а затем кэшируется; при каждом изменении исходного файла Lua необходимо перезагружать конфигурацию Nginx. Во время разработки кэш кода Lua можно временно отключить, установив для lua_code_cache значение off в nginx.conf, чтобы не перезагружать Nginx.

Для этой директивы требуется модуль ngx_devel_kit.

content_by_lua

синтаксис: content_by_lua <lua-script-str>

контекст: location, location if

фаза: content

ПРИМЕЧАНИЕ После выпуска v0.9.17 использовать эту директиву не рекомендуется. Вместо неё используйте директиву content_by_lua_block.

Подобно директиве content_by_lua_block, но принимает исходный код Lua непосредственно в строковом литерале Nginx (что требует экранирования специальных символов).

Например:

content_by_lua '
    ngx.say("I need no extra escaping here, for example: \r\nblah")
';

content_by_lua_block

синтаксис: content_by_lua_block { lua-script }

контекст: location, location if

фаза: content

Например:

content_by_lua_block {
    ngx.say("I need no extra escaping here, for example: \r\nblah")
}

Работает как «обработчик содержимого» и выполняет строку кода Lua, указанную в { lua-script }, для каждого запроса. Код Lua может вызывать функции API и выполняется в новой корутине в отдельном глобальном окружении (то есть в песочнице).

Не используйте эту директиву одновременно с другими директивами обработчиков содержимого в одном блоке location. Например, эту директиву нельзя использовать в одном блоке location с директивой proxy_pass.

Эта директива впервые появилась в выпуске v0.9.17.

content_by_lua_file

синтаксис: content_by_lua_file <path-to-lua-script-file>

контекст: location, location if

фаза: content

Эквивалентна content_by_lua_block, за исключением того, что файл, указанный в <path-to-lua-script-file>, содержит код Lua или, начиная с выпуска v0.5.0rc32, байт-код LuaJIT, который будет выполнен.

Если файл не найден, будет возвращён код состояния 404 Not Found; если при чтении других файлов возникнут ошибки, будет возвращён код состояния 503 Service Temporarily Unavailable.

Для повышения гибкости в строке <path-to-lua-script-file> можно использовать переменные Nginx. Однако это сопряжено с определёнными рисками и обычно не рекомендуется.

Если указан относительный путь, например foo/bar.lua, он будет преобразован в абсолютный путь относительно пути server prefix, определяемого параметром командной строки -p PATH при запуске сервера Nginx.

Если кэш кода Lua включён (по умолчанию), пользовательский код загружается при первом запросе, а затем кэшируется; при каждом изменении исходного файла Lua необходимо перезагружать конфигурацию Nginx. Во время разработки кэш кода Lua можно временно отключить, установив для lua_code_cache значение off в nginx.conf, чтобы не перезагружать Nginx.

Для динамического выбора файла в пути поддерживаются переменные Nginx. Например:

# CAUTION: contents in nginx var must be carefully filtered,
# otherwise there'll be great security risk!
location ~ ^/app/([-_a-zA-Z0-9/]+) {
    set $path $1;
    content_by_lua_file /path/to/lua/app/root/$path.lua;
}

Однако остерегайтесь вредоносных пользовательских данных и всегда тщательно проверяйте или фильтруйте компоненты пути, предоставленные пользователем.

server_rewrite_by_lua_block

синтаксис: server_rewrite_by_lua_block { lua-script }

контекст: http, server

фаза: server rewrite

Работает как обработчик фазы переписывания на уровне сервера и выполняет строку кода Lua, указанную в { lua-script }, для каждого запроса. Код Lua может вызывать функции API и выполняется в новой корутине в отдельном глобальном окружении (то есть в песочнице).

server {
    ...

    server_rewrite_by_lua_block {
        ngx.ctx.a = "server_rewrite_by_lua_block in http"
    }

    location /lua {
        content_by_lua_block {
            ngx.say(ngx.ctx.a)
            ngx.log(ngx.INFO, ngx.ctx.a)
       	}
    }
}

Как и любые другие обработчики фазы переписывания, server_rewrite_by_lua_block также выполняется для подзапросов.

server {
    server_rewrite_by_lua_block {
        ngx.log(ngx.INFO, "is_subrequest:", ngx.is_subrequest)
    }

    location /lua {
        content_by_lua_block {
            local res = ngx.location.capture("/sub")
            ngx.print(res.body)
        }
    }

    location /sub {
        content_by_lua_block {
            ngx.say("OK")
        }
    }
}

Обратите внимание: при вызове ngx.exit(ngx.OK) внутри обработчика server_rewrite_by_lua_block обработка запроса Nginx всё равно продолжится и перейдёт к обработчику содержимого. Чтобы завершить текущий запрос из обработчика server_rewrite_by_lua_block, вызовите ngx.exit с кодом состояния >= 200 (ngx.HTTP_OK) и < 300 (ngx.HTTP_SPECIAL_RESPONSE) для успешного завершения либо с ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR) (или соответствующим кодом) в случае ошибки.

server_rewrite_by_lua_block {
    ngx.exit(503)
}

location /bar {
    ...
    # never exec
}

server_rewrite_by_lua_file

синтаксис: server_rewrite_by_lua_file <path-to-lua-script-file>

контекст: http, server

фаза: server rewrite

Эквивалентна server_rewrite_by_lua_block, за исключением того, что файл, указанный в <path-to-lua-script-file>, содержит код Lua или, начиная с выпуска v0.10.22, байт-код LuaJIT, который будет выполнен.

Для повышения гибкости в строке <path-to-lua-script-file> можно использовать переменные Nginx. Однако это сопряжено с определёнными рисками и обычно не рекомендуется.

Если указан относительный путь, например foo/bar.lua, он будет преобразован в абсолютный путь относительно пути server prefix, определяемого параметром командной строки -p PATH при запуске сервера Nginx.

Если кэш кода Lua включён (по умолчанию), пользовательский код загружается при первом запросе, а затем кэшируется; при каждом изменении исходного файла Lua необходимо перезагружать конфигурацию Nginx. Во время разработки кэш кода Lua можно временно отключить, установив для lua_code_cache значение off в nginx.conf, чтобы не перезагружать Nginx.

rewrite_by_lua

синтаксис: rewrite_by_lua <lua-script-str>

контекст: http, server, location, location if

фаза: rewrite tail

ПРИМЕЧАНИЕ Использование этой директивы не рекомендуется начиная с выпуска v0.9.17. Вместо неё используйте директиву rewrite_by_lua_block.

Подобно директиве rewrite_by_lua_block, но принимает исходный код Lua непосредственно в строковом литерале Nginx (для чего требуется экранирование специальных символов).

Например,

rewrite_by_lua '
    do_something("hello, world!\nhiya\n")
';

rewrite_by_lua_block

синтаксис: rewrite_by_lua_block { lua-script }

контекст: http, server, location, location if

фаза: rewrite tail

Работает как обработчик фазы rewrite и выполняет строку кода Lua, указанную в { lua-script }, для каждого запроса. Код Lua может выполнять вызовы API и выполняется в новой запущенной корутине в независимом глобальном окружении (то есть в песочнице).

Обратите внимание, что этот обработчик всегда запускается после стандартного ngx_http_rewrite_module. Поэтому следующий пример будет работать ожидаемым образом:

location /foo {
    set $a 12; # create and initialize $a
    set $b ""; # create and initialize $b
    rewrite_by_lua_block {
        ngx.var.b = tonumber(ngx.var.a) + 1
    }
    echo "res = $b";
}

поскольку set $a 12 и set $b "" выполняются до rewrite_by_lua_block.

С другой стороны, следующий пример не будет работать ожидаемым образом:

?  location /foo {
?      set $a 12; # create and initialize $a
?      set $b ''; # create and initialize $b
?      rewrite_by_lua_block {
?          ngx.var.b = tonumber(ngx.var.a) + 1
?      }
?      if ($b = '13') {
?         rewrite ^ /bar redirect;
?         break;
?      }
?
?      echo "res = $b";
?  }

поскольку if выполняется до rewrite_by_lua_block, даже если в конфигурации оно указано после rewrite_by_lua_block.

Правильный способ сделать это выглядит следующим образом:

location /foo {
    set $a 12; # create and initialize $a
    set $b ''; # create and initialize $b
    rewrite_by_lua_block {
        ngx.var.b = tonumber(ngx.var.a) + 1
        if tonumber(ngx.var.b) == 13 then
            return ngx.redirect("/bar")
        end
    }

    echo "res = $b";
}

Обратите внимание, что функциональность модуля ngx_eval можно приблизительно воспроизвести с помощью rewrite_by_lua_block. Например,

location / {
    eval $res {
        proxy_pass http://foo.com/check-spam;
    }

    if ($res = 'spam') {
        rewrite ^ /terms-of-use.html redirect;
    }

    fastcgi_pass ...;
}

можно реализовать в ngx_lua следующим образом:

location = /check-spam {
    internal;
    proxy_pass http://foo.com/check-spam;
}

location / {
    rewrite_by_lua_block {
        local res = ngx.location.capture("/check-spam")
        if res.body == "spam" then
            return ngx.redirect("/terms-of-use.html")
        end
    }

    fastcgi_pass ...;
}

Как и любые другие обработчики фазы rewrite, rewrite_by_lua_block также запускается в подзапросах.

Обратите внимание: при вызове ngx.exit(ngx.OK) внутри обработчика rewrite_by_lua_block поток управления обработкой запроса Nginx всё равно продолжится и дойдёт до обработчика содержимого. Чтобы завершить текущий запрос внутри обработчика rewrite_by_lua_block, вызовите ngx.exit с кодом состояния >= 200 (ngx.HTTP_OK) и кодом состояния < 300 (ngx.HTTP_SPECIAL_RESPONSE) для успешного завершения либо ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR) (или его аналоги) в случае ошибки.

Если директива rewrite модуля ngx_http_rewrite_module используется для изменения URI и повторного поиска location (внутреннего перенаправления), то последовательности кода rewrite_by_lua_block или rewrite_by_lua_file_block в текущем location выполнены не будут. Например,

location /foo {
    rewrite ^ /bar;
    rewrite_by_lua_block {
        ngx.exit(503)
    }
}
location /bar {
    ...
}

В этом случае код Lua ngx.exit(503) никогда не выполнится. То же произойдёт, если используется rewrite ^ /bar last, поскольку оно также инициирует внутреннее перенаправление. Если вместо этого использовать модификатор break, внутреннего перенаправления не будет и код rewrite_by_lua_block выполнится.

Код rewrite_by_lua_block всегда выполняется в конце фазы обработки запроса rewrite, если не включена директива rewrite_by_lua_no_postpone.

Эта директива впервые появилась в выпуске v0.9.17.

rewrite_by_lua_file

синтаксис: rewrite_by_lua_file <path-to-lua-script-file>

контекст: http, server, location, location if

фаза: rewrite tail

Эквивалентна rewrite_by_lua_block, но файл, указанный в <path-to-lua-script-file>, содержит код Lua или, начиная с выпуска v0.5.0rc32, байт-код LuaJIT, который необходимо выполнить.

Для большей гибкости в строке <path-to-lua-script-file> можно использовать переменные Nginx. Однако это сопряжено с некоторыми рисками и обычно не рекомендуется.

Если указан относительный путь, например foo/bar.lua, он будет преобразован в абсолютный путь относительно пути server prefix, определяемого параметром командной строки -p PATH при запуске сервера Nginx.

Если кэш кода Lua включён (по умолчанию), пользовательский код загружается и кэшируется при первом запросе, а конфигурацию Nginx необходимо перезагружать при каждом изменении исходного файла Lua. Во время разработки кэш кода Lua можно временно отключить, изменив lua_code_cache на off в nginx.conf, чтобы не перезагружать Nginx.

Код rewrite_by_lua_file всегда выполняется в конце фазы обработки запроса rewrite, если не включена директива rewrite_by_lua_no_postpone.

Переменные Nginx поддерживаются в пути к файлу для динамического выбора, как и в content_by_lua_file.

access_by_lua

синтаксис: access_by_lua <lua-script-str>

контекст: http, server, location, location if

фаза: access tail

ПРИМЕЧАНИЕ Использование этой директивы не рекомендуется начиная с выпуска v0.9.17. Вместо неё используйте директиву access_by_lua_block.

Подобно директиве access_by_lua_block, но принимает исходный код Lua непосредственно в строковом литерале Nginx (для чего требуется экранирование специальных символов).

Например,

access_by_lua '
    do_something("hello, world!\nhiya\n")
';

access_by_lua_block

синтаксис: access_by_lua_block { lua-script }

контекст: http, server, location, location if

фаза: access tail

Работает как обработчик фазы access и выполняет строку кода Lua, указанную в { <lua-script }, для каждого запроса. Код Lua может выполнять вызовы API и выполняется в новой запущенной корутине в независимом глобальном окружении (то есть в песочнице).

Обратите внимание, что этот обработчик всегда запускается после стандартного ngx_http_access_module. Поэтому следующий пример будет работать ожидаемым образом:

location / {
    deny    192.168.1.1;
    allow   192.168.1.0/24;
    allow   10.1.1.0/16;
    deny    all;

    access_by_lua_block {
        local res = ngx.location.capture("/mysql", { ... })
        ...
    }

    # proxy_pass/fastcgi_pass/...
}

То есть, если IP-адрес клиента находится в чёрном списке, доступ будет запрещён до выполнения запроса к MySQL для более сложной аутентификации директивой access_by_lua_block.

Обратите внимание, что функциональность модуля ngx_auth_request можно приблизительно воспроизвести с помощью access_by_lua_block:

location / {
    auth_request /auth;

    # proxy_pass/fastcgi_pass/postgres_pass/...
}

можно реализовать в ngx_lua следующим образом:

location / {
    access_by_lua_block {
        local res = ngx.location.capture("/auth")

        if res.status == ngx.HTTP_OK then
            return
        end

        if res.status == ngx.HTTP_FORBIDDEN then
            ngx.exit(res.status)
        end

        ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
    }

    # proxy_pass/fastcgi_pass/postgres_pass/...
}

Как и другие обработчики фазы access, access_by_lua_block не запускается в подзапросах.

Обратите внимание: при вызове ngx.exit(ngx.OK) внутри обработчика access_by_lua_block поток управления обработкой запроса Nginx всё равно продолжится и дойдёт до обработчика содержимого. Чтобы завершить текущий запрос внутри обработчика access_by_lua_block, вызовите ngx.exit с кодом состояния >= 200 (ngx.HTTP_OK) и кодом состояния < 300 (ngx.HTTP_SPECIAL_RESPONSE) для успешного завершения либо ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR) (или его аналоги) в случае ошибки.

Начиная с выпуска v0.9.20, можно использовать директиву access_by_lua_no_postpone, чтобы управлять временем запуска этого обработчика внутри фазы обработки запроса Nginx «access».

Эта директива впервые появилась в выпуске v0.9.17.

access_by_lua_file

синтаксис: access_by_lua_file <path-to-lua-script-file>

контекст: http, server, location, location if

фаза: access tail

Эквивалентна access_by_lua_block, но файл, указанный в <path-to-lua-script-file>, содержит код Lua или, начиная с выпуска v0.5.0rc32, байт-код LuaJIT, который необходимо выполнить.

Для большей гибкости в строке <path-to-lua-script-file> можно использовать переменные Nginx. Однако это сопряжено с некоторыми рисками и обычно не рекомендуется.

Если указан относительный путь, например foo/bar.lua, он будет преобразован в абсолютный путь относительно пути server prefix, определяемого параметром командной строки -p PATH при запуске сервера Nginx.

Если кэш кода Lua включён (по умолчанию), пользовательский код загружается и кэшируется при первом запросе, а конфигурацию Nginx необходимо перезагружать при каждом изменении исходного файла Lua. Во время разработки кэш кода Lua можно временно отключить, изменив lua_code_cache на off в nginx.conf, чтобы не перезагружать Nginx многократно.

Переменные Nginx поддерживаются в пути к файлу для динамического выбора, как и в content_by_lua_file.

header_filter_by_lua

синтаксис: header_filter_by_lua <lua-script-str>

контекст: http, server, location, location if

фаза: output-header-filter

ПРИМЕЧАНИЕ Использование этой директивы не рекомендуется начиная с выпуска v0.9.17. Вместо неё используйте директиву header_filter_by_lua_block.

Подобно директиве header_filter_by_lua_block, но принимает исходный код Lua непосредственно в строковом литерале Nginx (для чего требуется экранирование специальных символов).

Например,

header_filter_by_lua '
    ngx.header["content-length"] = nil
';

Эта директива впервые появилась в выпуске v0.2.1rc20.

header_filter_by_lua_block

синтаксис: header_filter_by_lua_block { lua-script }

контекст: http, server, location, location if

фаза: output-header-filter

Использует код Lua, указанный в { lua-script }, для определения фильтра выходных заголовков.

Обратите внимание, что следующие функции API в этом контексте сейчас отключены:

  • Функции API вывода (например, ngx.say и ngx.send_headers)
  • Функции API управления (например, ngx.redirect и ngx.exec)
  • Функции API подзапросов (например, ngx.location.capture и ngx.location.capture_multi)
  • Функции API cosocket (например, ngx.socket.tcp и ngx.req.socket).

Вот пример переопределения заголовка ответа (или его добавления, если он отсутствует) в нашем фильтре заголовков на Lua:

location / {
    proxy_pass http://mybackend;
    header_filter_by_lua_block {
        ngx.header.Foo = "blah"
    }
}

Эта директива впервые появилась в выпуске v0.9.17.

header_filter_by_lua_file

синтаксис: header_filter_by_lua_file <path-to-lua-script-file>

контекст: http, server, location, location if

фаза: output-header-filter

Эквивалентна header_filter_by_lua_block, но файл, указанный в <path-to-lua-script-file>, содержит код Lua или, начиная с выпуска v0.5.0rc32, байт-код LuaJIT, который необходимо выполнить.

Если указан относительный путь, например foo/bar.lua, он будет преобразован в абсолютный путь относительно пути server prefix, определяемого параметром командной строки -p PATH при запуске сервера Nginx.

Эта директива впервые появилась в выпуске v0.2.1rc20.

body_filter_by_lua

синтаксис: body_filter_by_lua <lua-script-str>

контекст: http, server, location, location if

фаза: output-body-filter

ПРИМЕЧАНИЕ Использование этой директивы не рекомендуется начиная с выпуска v0.9.17. Вместо неё используйте директиву body_filter_by_lua_block.

Подобно директиве body_filter_by_lua_block, но принимает исходный код Lua непосредственно в строковом литерале Nginx (для чего требуется экранирование специальных символов).

Например,

body_filter_by_lua '
    local data, eof = ngx.arg[1], ngx.arg[2]
';

Эта директива впервые появилась в выпуске v0.5.0rc32.

body_filter_by_lua_block

синтаксис: body_filter_by_lua_block { lua-script-str }

контекст: http, server, location, location if

фаза: output-body-filter

Использует код Lua, указанный в { lua-script }, для определения фильтра выходного тела ответа.

Входной фрагмент данных передаётся через ngx.arg[1] (в виде строкового значения Lua), а флаг «eof», обозначающий конец потока данных тела ответа, — через ngx.arg[2] (в виде логического значения Lua).

Внутри Nginx флаг «eof» — это просто флаг last_buf (для основных запросов) или last_in_chain (для подзапросов) буферов звеньев цепочки Nginx. (До выпуска v0.7.14 флаг «eof» в подзапросах вообще не работал.)

Поток выходных данных можно немедленно прервать, выполнив следующую инструкцию Lua:

return ngx.ERROR

Это обрежет тело ответа и обычно приведёт к неполному и недопустимому ответу.

Код Lua может передать собственную изменённую версию входного фрагмента данных последующим фильтрам выходного тела Nginx, переопределив ngx.arg[1] строкой Lua или таблицей строк Lua. Например, чтобы преобразовать все строчные буквы в теле ответа, достаточно написать:

location / {
    proxy_pass http://mybackend;
    body_filter_by_lua_block {
        ngx.arg[1] = string.upper(ngx.arg[1])
    }
}

Если присвоить nil или пустую строку Lua значению ngx.arg[1], фрагмент данных вообще не будет передан последующим фильтрам вывода Nginx.

Аналогичным образом новый флаг «eof» можно задать, присвоив логическое значение ngx.arg[2]. Например,

location /t {
    echo hello world;
    echo hiya globe;

    body_filter_by_lua_block {
        local chunk = ngx.arg[1]
        if string.match(chunk, "hello") then
            ngx.arg[2] = true  -- new eof
            return
        end

        -- just throw away any remaining chunk data
        ngx.arg[1] = nil
    }
}

Тогда GET /t просто вернёт результат

hello world

То есть, когда фильтр тела получает фрагмент, содержащий слово «hello», он немедленно устанавливает флаг «eof» в true, в результате чего ответ обрезается, но остаётся допустимым.

Если код Lua может изменить длину тела ответа, необходимо всегда очищать заголовок ответа Content-Length (если он есть) в фильтре заголовков, чтобы обеспечить потоковую передачу вывода, например:

location /foo {
    # fastcgi_pass/proxy_pass/...

    header_filter_by_lua_block {
        ngx.header.content_length = nil
    }
    body_filter_by_lua_block {
        ngx.arg[1] = string.len(ngx.arg[1]) .. "\n"
    }
}

Обратите внимание, что следующие функции API в этом контексте сейчас отключены из-за ограничений текущей реализации фильтра вывода Nginx:

  • Функции API вывода (например, ngx.say и ngx.send_headers)
  • Функции API управления (например, ngx.exit и ngx.exec)
  • Функции API подзапросов (например, ngx.location.capture и ngx.location.capture_multi)
  • Функции API cosocket (например, ngx.socket.tcp и ngx.req.socket).

Фильтры вывода Nginx могут вызываться несколько раз для одного запроса, поскольку тело ответа может передаваться фрагментами. Поэтому код Lua, указанный в этой директиве, также может выполняться несколько раз за время обработки одного HTTP-запроса.

Эта директива впервые появилась в выпуске v0.9.17.

body_filter_by_lua_file

синтаксис: body_filter_by_lua_file <path-to-lua-script-file>

контекст: http, server, location, location if

фаза: output-body-filter

Эквивалентна body_filter_by_lua_block, но файл, указанный в <path-to-lua-script-file>, содержит код Lua или, начиная с выпуска v0.5.0rc32, байт-код LuaJIT, который необходимо выполнить.

Если указан относительный путь, например foo/bar.lua, он будет преобразован в абсолютный путь относительно пути server prefix, определяемого параметром командной строки -p PATH при запуске сервера Nginx.

Эта директива впервые появилась в выпуске v0.5.0rc32.

log_by_lua

синтаксис: log_by_lua <lua-script-str>

контекст: http, server, location, location if

фаза: log

ПРИМЕЧАНИЕ Использование этой директивы не рекомендуется начиная с выпуска v0.9.17. Вместо неё используйте директиву log_by_lua_block.

Подобно директиве log_by_lua_block, но принимает исходный код Lua непосредственно в строковом литерале Nginx (для чего требуется экранирование специальных символов).

Например,

log_by_lua '
    print("I need no extra escaping here, for example: \r\nblah")
';

Эта директива впервые появилась в выпуске v0.5.0rc31.

log_by_lua_block

синтаксис: log_by_lua_block { lua-script }

контекст: http, server, location, location if

фаза: log

Выполняет встроенный исходный код Lua в фазе обработки запроса { lua-script } на этапе log. Эта директива не заменяет текущие журналы доступа, а выполняется перед их записью.

Обратите внимание, что следующие функции API в этом контексте сейчас отключены:

  • Функции API вывода (например, ngx.say и ngx.send_headers)
  • Функции API управления (например, ngx.exit)
  • Функции API подзапросов (например, ngx.location.capture и ngx.location.capture_multi)
  • Функции API cosocket (например, ngx.socket.tcp и ngx.req.socket).

Вот пример сбора среднего значения данных для $upstream_response_time:

lua_shared_dict log_dict 5M;

server {
    location / {
        proxy_pass http://mybackend;

        log_by_lua_block {
            local log_dict = ngx.shared.log_dict
            local upstream_time = tonumber(ngx.var.upstream_response_time)

            local sum = log_dict:get("upstream_time-sum") or 0
            sum = sum + upstream_time
            log_dict:set("upstream_time-sum", sum)

            local newval, err = log_dict:incr("upstream_time-nb", 1)
            if not newval and err == "not found" then
                log_dict:add("upstream_time-nb", 0)
                log_dict:incr("upstream_time-nb", 1)
            end
        }
    }

    location = /status {
        content_by_lua_block {
            local log_dict = ngx.shared.log_dict
            local sum = log_dict:get("upstream_time-sum")
            local nb = log_dict:get("upstream_time-nb")

            if nb and sum then
                ngx.say("average upstream response time: ", sum / nb,
                        " (", nb, " reqs)")
            else
                ngx.say("no data yet")
            end
        }
    }
}

Эта директива впервые появилась в выпуске v0.9.17.

log_by_lua_file

синтаксис: log_by_lua_file <path-to-lua-script-file>

контекст: http, server, location, location if

фаза: log

Эквивалентна log_by_lua_block, но файл, указанный в <path-to-lua-script-file>, содержит код Lua или, начиная с выпуска v0.5.0rc32, байт-код LuaJIT, который необходимо выполнить.

Если указан относительный путь, например foo/bar.lua, он будет преобразован в абсолютный путь относительно пути server prefix, определяемого параметром командной строки -p PATH при запуске сервера Nginx.

Эта директива впервые появилась в выпуске v0.5.0rc31.

balancer_by_lua_block

синтаксис: balancer_by_lua_block { lua-script }

контекст: upstream

фаза: content

Эта директива выполняет код Lua в качестве балансировщика upstream для любых сущностей upstream, определённых в блоке конфигурации upstream {}.

Например,

upstream foo {
    server 127.0.0.1;
    balancer_by_lua_block {
        -- use Lua to do something interesting here
        -- as a dynamic balancer
    }
}

server {
    location / {
        proxy_pass http://foo;
    }
}

Полученный балансировщик нагрузки на Lua может работать с любыми существующими модулями upstream Nginx, такими как ngx_proxy и ngx_fastcgi.

Кроме того, балансировщик нагрузки на Lua может использовать стандартный механизм пула соединений upstream, то есть стандартную директиву keepalive. Убедитесь, что директива keepalive указана после этой директивы balancer_by_lua_block в одном блоке конфигурации upstream {}.

Балансировщик нагрузки на Lua может полностью игнорировать список серверов, определённый в блоке upstream {}, и выбирать узел из полностью динамического списка серверов (который может меняться даже для каждого запроса) с помощью модуля ngx.balancer из библиотеки lua-resty-core.

Обработчик кода Lua, зарегистрированный этой директивой, может вызываться несколько раз в рамках одного входящего запроса, если механизм upstream Nginx повторяет запрос при условиях, заданных такими директивами, как proxy_next_upstream.

В этом контексте выполнения кода Lua не поддерживается приостановка, поэтому API Lua, которые могут приостанавливать выполнение (например, cosocket и «лёгкие потоки»), отключены. Обычно это ограничение можно обойти, выполнив такие операции в обработчике более ранней фазы (например, access_by_lua*) и передав результат в этот контекст через таблицу ngx.ctx.

Эта директива впервые появилась в выпуске v0.10.0.

balancer_by_lua_file

синтаксис: balancer_by_lua_file <path-to-lua-script-file>

контекст: upstream

фаза: content

Эквивалентна balancer_by_lua_block, но файл, указанный в <path-to-lua-script-file>, содержит код Lua или, начиная с выпуска v0.5.0rc32, байт-код LuaJIT, который необходимо выполнить.

Если указан относительный путь, например foo/bar.lua, он будет преобразован в абсолютный путь относительно пути server prefix, определяемого параметром командной строки -p PATH при запуске сервера Nginx.

Эта директива впервые появилась в выпуске v0.10.0.

balancer_keepalive

синтаксис: balancer_keepalive <total-connections>

контекст: upstream

фаза: loading-config

Параметр total-connections задаёт максимальное количество неактивных keepalive-соединений с upstream-серверами, сохраняемых в кэше каждого рабочего процесса. При превышении этого значения закрываются соединения, которые дольше всего не использовались.

Особо отметим, что директива keepalive не ограничивает общее количество соединений с upstream-серверами, которые может открыть рабочий процесс nginx. Значение параметра connections следует установить достаточно малым, чтобы upstream-серверы также могли обрабатывать новые входящие соединения.

Эта директива впервые появилась в выпуске v0.10.21.

lua_need_request_body

синтаксис: lua_need_request_body <on|off>

значение по умолчанию: off

контекст: http, server, location, location if

фаза: зависит от использования

Определяет, следует ли принудительно считывать тело запроса перед выполнением rewrite/access/content_by_lua* или нет. Ядро Nginx по умолчанию не считывает тело запроса клиента. Если данные тела запроса необходимы, эту директиву следует включить, установив on, либо вызвать функцию ngx.req.read_body в коде Lua.

Чтобы считывать данные тела запроса через переменную $request_body, значение client_body_buffer_size должно совпадать со значением client_max_body_size. Если длина содержимого превышает client_body_buffer_size, но меньше client_max_body_size, Nginx сохраняет данные во временный файл на диске, из-за чего переменная $request_body будет пустой.

Если в текущем location присутствуют директивы rewrite_by_lua*, тело запроса будет считано непосредственно перед выполнением кода rewrite_by_lua* (а также на фазе rewrite). Аналогично, если указана только директива content_by_lua, тело запроса будет считано лишь перед выполнением кода Lua обработчика содержимого (то есть тело запроса будет считано во время фазы content).

Однако для более точного управления процессом чтения тела запроса рекомендуется использовать функции ngx.req.read_body и ngx.req.discard_body.

Это также относится к access_by_lua*.

ssl_client_hello_by_lua_block

синтаксис: ssl_client_hello_by_lua_block { lua-script }

контекст: http, server

фаза: right-after-client-hello-message-was-processed

Эта директива выполняет пользовательский код Lua, когда Nginx собирается выполнить постобработку сообщения SSL client hello для нисходящих SSL-соединений (https).

Она особенно полезна для динамической настройки протоколов SSL в соответствии с SNI.

Она также полезна для выполнения пользовательских операций с учетом информации о конкретном соединении, содержащейся в сообщении client hello.

Например, можно разобрать пользовательское расширение client hello и выполнить соответствующую обработку на чистом Lua.

Этот обработчик Lua запускается всегда, независимо от того, возобновляется ли SSL-сеанс (с помощью идентификаторов SSL-сеансов или билетов сеансов TLS). При этом обработчик Lua ssl_certificate_by_lua* запускается только при инициировании полного SSL-рукопожатия.

Модули Lua ngx.ssl.clienthello, предоставляемые библиотекой lua-resty-core, особенно полезны в этом контексте.

Обратите внимание, что этот обработчик запускается на очень раннем этапе SSL-рукопожатия, до разбора расширений SSL client hello. Поэтому нельзя использовать некоторые API Lua, например ssl.server_name(), которые зависят от обработки на более позднем этапе.

Также обратите внимание, что для нескольких виртуальных серверов с одинаковыми IP-адресом и портом действительна только директива в сервере по умолчанию.

Ниже приведен простой пример одновременного использования модуля ngx.ssl.clienthello:

server {
    listen 443 ssl;
    server_name   test.com;
    ssl_certificate /path/to/cert.crt;
    ssl_certificate_key /path/to/key.key;
    ssl_client_hello_by_lua_block {
        local ssl_clt = require "ngx.ssl.clienthello"
        local host, err = ssl_clt.get_client_hello_server_name()
        if host == "test.com" then
            ssl_clt.set_protocols({"TLSv1", "TLSv1.1"})
        elseif host == "test2.com" then
            ssl_clt.set_protocols({"TLSv1.2", "TLSv1.3"})
        elseif not host then
            ngx.log(ngx.ERR, "failed to get the SNI name: ", err)
            ngx.exit(ngx.ERROR)
        else
            ngx.log(ngx.ERR, "unknown SNI name: ", host)
            ngx.exit(ngx.ERROR)
        end
    }
    ...
}
server {
    listen 443 ssl;
    server_name   test2.com;
    ssl_certificate /path/to/cert.crt;
    ssl_certificate_key /path/to/key.key;
    ...
}

Дополнительные сведения см. в официальной документации модулей Lua ngx.ssl.clienthello.

Необработанные исключения Lua в пользовательском коде Lua немедленно прерывают текущий SSL-сеанс. То же происходит при вызове ngx.exit с кодом ошибки, например ngx.ERROR.

Этот контекст выполнения кода Lua поддерживает приостановку выполнения, поэтому в нем доступны API Lua, которые могут приостанавливать выполнение (например, cosocket, ожидание и «легкие потоки»).

Обратите внимание: необходимо настроить ssl_certificate и ssl_certificate_key, чтобы при запуске NGINX не возникала следующая ошибка:

nginx: [emerg] no ssl configured for the server

Для этой директивы требуется OpenSSL версии 1.1.1 или более поздней.

Если вы используете официальные готовые пакеты OpenResty версии 1.21.4.1 или более поздней, все должно работать без дополнительной настройки.

Если вы не используете ядро Nginx, поставляемое с OpenResty версии 1.21.4.1 или более поздней, потребуется применить патчи к стандартному ядру Nginx:

https://openresty.org/en/nginx-ssl-patches.html

Эта директива впервые появилась в выпуске v0.10.21.

ssl_client_hello_by_lua_file

синтаксис: ssl_client_hello_by_lua_file <path-to-lua-script-file>

контекст: http, server

фаза: right-after-client-hello-message-was-processed

Эквивалент директивы ssl_client_hello_by_lua_block, за исключением того, что файл, указанный в <path-to-lua-script-file>, содержит код Lua или, начиная с выпуска v0.5.0rc32, байт-код LuaJIT, который необходимо выполнить.

Если указан относительный путь, например foo/bar.lua, он будет преобразован в абсолютный путь относительно пути server prefix, заданного параметром командной строки -p PATH при запуске сервера Nginx.

Эта директива впервые появилась в выпуске v0.10.21.

ssl_certificate_by_lua_block

синтаксис: ssl_certificate_by_lua_block { lua-script }

контекст: server

фаза: right-before-SSL-handshake

Эта директива выполняет пользовательский код Lua, когда Nginx собирается начать SSL-рукопожатие для нисходящих SSL-соединений (https).

Она особенно полезна для настройки цепочки сертификатов SSL и соответствующего закрытого ключа отдельно для каждого запроса. Кроме того, она позволяет неблокирующим образом загружать такие конфигурации рукопожатия с удаленного сервера (например, с помощью API cosocket). Здесь также можно выполнять обработку OCSP stapling для каждого запроса на чистом Lua.

Еще один типичный вариант использования — неблокирующее управление трафиком SSL-рукопожатия в этом контексте, например с помощью библиотеки lua-resty-limit-traffic#readme.

Также можно выполнять интересные действия с запросами SSL-рукопожатия со стороны клиента, например выборочно отклонять старые SSL-клиенты, использующие протокол SSLv3 или более ранний.

Модули Lua ngx.ssl и ngx.ocsp, предоставляемые библиотекой lua-resty-core, особенно полезны в этом контексте. С помощью API Lua, предоставляемых этими модулями, можно изменять цепочку сертификатов SSL и закрытый ключ для устанавливаемого SSL-соединения.

Однако этот обработчик Lua не запускается, если Nginx/OpenSSL успешно возобновляет SSL-сеанс текущего SSL-соединения с помощью идентификаторов SSL-сеансов или билетов сеансов TLS. Иными словами, этот обработчик Lua запускается только тогда, когда Nginx необходимо инициировать полное SSL-рукопожатие.

Ниже приведен простой пример одновременного использования модуля ngx.ssl:

server {
    listen 443 ssl;
    server_name   test.com;

    ssl_certificate_by_lua_block {
        print("About to initiate a new SSL handshake!")
    }

    location / {
        root html;
    }
}

Более сложные примеры см. в официальной документации модулей Lua ngx.ssl и ngx.ocsp.

Необработанные исключения Lua в пользовательском коде Lua немедленно прерывают текущий SSL-сеанс. То же происходит при вызове ngx.exit с кодом ошибки, например ngx.ERROR.

Этот контекст выполнения кода Lua поддерживает приостановку выполнения, поэтому в нем доступны API Lua, которые могут приостанавливать выполнение (например, cosocket, ожидание и «легкие потоки»).

Однако обратите внимание: директивы ssl_certificate и ssl_certificate_key все равно необходимо настроить, даже если вы не собираетесь использовать этот статический сертификат и закрытый ключ. Это необходимо, поскольку ядро NGINX требует наличия этих директив, иначе при запуске NGINX появится следующая ошибка:

nginx: [emerg] no ssl configured for the server

Для этой директивы требуется OpenSSL версии 1.0.2e или более поздней.

Если вы используете официальные готовые пакеты OpenResty версии 1.9.7.2 или более поздней, все должно работать без дополнительной настройки.

Если вы не используете ядро Nginx, поставляемое с OpenResty версии 1.9.7.2 или более поздней, потребуется применить патчи к стандартному ядру Nginx:

https://openresty.org/en/nginx-ssl-patches.html

Эта директива впервые появилась в выпуске v0.10.0.

ssl_certificate_by_lua_file

синтаксис: ssl_certificate_by_lua_file <path-to-lua-script-file>

контекст: server

фаза: right-before-SSL-handshake

Эквивалент директивы ssl_certificate_by_lua_block, за исключением того, что файл, указанный в <path-to-lua-script-file>, содержит код Lua или, начиная с выпуска v0.5.0rc32, байт-код LuaJIT, который необходимо выполнить.

Если указан относительный путь, например foo/bar.lua, он будет преобразован в абсолютный путь относительно пути server prefix, заданного параметром командной строки -p PATH при запуске сервера Nginx.

Эта директива впервые появилась в выпуске v0.10.0.

ssl_session_fetch_by_lua_block

синтаксис: ssl_session_fetch_by_lua_block { lua-script }

контекст: http

фаза: right-before-SSL-handshake

Эта директива выполняет код Lua для поиска и загрузки SSL-сеанса (если он существует) по идентификатору сеанса, указанному в текущем запросе SSL-рукопожатия для нисходящего соединения.

API Lua для получения текущего идентификатора сеанса и загрузки кэшированных данных SSL-сеанса предоставляется модулем Lua ngx.ssl.session, входящим в библиотеку lua-resty-core.

В этом контексте доступны API Lua, которые могут приостанавливать выполнение, например ngx.sleep и cosocket.

Этот обработчик вместе с обработчиком ssl_session_store_by_lua* можно использовать для реализации механизмов распределенного кэширования на чистом Lua (например, на основе API cosocket). Если кэшированный SSL-сеанс найден и загружен в контекст текущего SSL-соединения, можно сразу инициировать возобновление SSL-сеанса и пропустить процесс полного SSL-рукопожатия, который требует значительных затрат процессорного времени.

Обратите внимание, что билеты сеансов TLS работают совершенно иначе: при их использовании ответственность за кэширование состояния SSL-сеанса лежит на клиентах. Возобновление SSL-сеанса на основе билетов сеансов TLS происходит автоматически, без вызова этого обработчика (как и обработчика ssl_session_store_by_lua*). Этот обработчик предназначен главным образом для старых или менее функциональных SSL-клиентов, которые могут использовать SSL-сеансы только с идентификаторами сеансов.

Если одновременно указана директива ssl_certificate_by_lua*, этот обработчик обычно запускается раньше нее. Если SSL-сеанс найден и успешно загружен для текущего SSL-соединения, происходит возобновление SSL-сеанса, поэтому обработчик ssl_certificate_by_lua* полностью пропускается. В этом случае Nginx также пропускает обработчик ssl_session_store_by_lua*, что вполне очевидно.

Чтобы без труда локально протестировать этот обработчик в современном веб-браузере, можно временно добавить следующую строку в блок сервера https, чтобы отключить поддержку билетов сеансов TLS:

ssl_session_tickets off;

Но не забудьте закомментировать эту строку перед публикацией сайта.

Если вы используете официальные готовые пакеты OpenResty версии 1.11.2.1 или более поздней, все должно работать без дополнительной настройки.

Если вы не используете один из пакетов OpenSSL, предоставляемых OpenResty, для использования этой директивы потребуется применить патчи к OpenSSL:

https://openresty.org/en/openssl-patches.html

Аналогично, если вы не используете ядро Nginx, поставляемое с OpenResty версии 1.11.2.1 или более поздней, потребуется применить патчи к стандартному ядру Nginx:

https://openresty.org/en/nginx-ssl-patches.html

Эта директива впервые появилась в выпуске v0.10.6.

Обратите внимание: начиная с выпуска v0.10.7 эту директиву можно использовать только в контексте http, поскольку возобновление SSL-сеанса происходит до выбора сервера по имени.

ssl_session_fetch_by_lua_file

синтаксис: ssl_session_fetch_by_lua_file <path-to-lua-script-file>

контекст: http

фаза: right-before-SSL-handshake

Эквивалент директивы ssl_session_fetch_by_lua_block, за исключением того, что файл, указанный в <path-to-lua-script-file>, содержит код Lua или, точнее, байт-код LuaJIT, который необходимо выполнить.

Если указан относительный путь, например foo/bar.lua, он будет преобразован в абсолютный путь относительно пути server prefix, заданного параметром командной строки -p PATH при запуске сервера Nginx.

Эта директива впервые появилась в выпуске v0.10.6.

Обратите внимание: начиная с выпуска v0.10.7 эту директиву можно использовать только в контексте http (поскольку возобновление SSL-сеанса происходит до выбора сервера по имени).

ssl_session_store_by_lua_block

синтаксис: ssl_session_store_by_lua_block { lua-script }

контекст: http

фаза: right-after-SSL-handshake

Эта директива выполняет код Lua для получения и сохранения SSL-сеанса (если он существует) по идентификатору сеанса, указанному в текущем запросе SSL-рукопожатия для нисходящего соединения. Сохраненные или кэшированные данные SSL-сеанса можно использовать для будущих SSL-соединений, чтобы возобновлять SSL-сеансы без полного SSL-рукопожатия, требующего значительных затрат процессорного времени.

API Lua, которые могут приостанавливать выполнение, например ngx.sleep и cosocket, в этом контексте отключены. Тем не менее можно использовать API ngx.timer.at, чтобы создавать таймеры с нулевой задержкой и асинхронно сохранять данные SSL-сеанса во внешних службах (например, redis или memcached).

API Lua для получения текущего идентификатора сеанса и связанных с ним данных состояния сеанса предоставляется модулем Lua ngx.ssl.session, входящим в библиотеку lua-resty-core.

Чтобы без труда локально протестировать этот обработчик в современном веб-браузере, можно временно добавить следующую строку в блок сервера https, чтобы отключить поддержку билетов сеансов TLS:

ssl_session_tickets off;

Но не забудьте закомментировать эту строку перед публикацией сайта.

Эта директива впервые появилась в выпуске v0.10.6.

Обратите внимание: начиная с выпуска v0.10.7 эту директиву можно использовать только в контексте http (поскольку возобновление SSL-сеанса происходит до выбора сервера по имени).

ssl_session_store_by_lua_file

синтаксис: ssl_session_store_by_lua_file <path-to-lua-script-file>

контекст: http

фаза: right-after-SSL-handshake

Эквивалент директивы ssl_session_store_by_lua_block, за исключением того, что файл, указанный в <path-to-lua-script-file>, содержит код Lua или, точнее, байт-код LuaJIT, который необходимо выполнить.

Если указан относительный путь, например foo/bar.lua, он будет преобразован в абсолютный путь относительно пути server prefix, заданного параметром командной строки -p PATH при запуске сервера Nginx.

Эта директива впервые появилась в выпуске v0.10.6.

Обратите внимание: начиная с выпуска v0.10.7 эту директиву можно использовать только в контексте http (поскольку возобновление SSL-сеанса происходит до выбора сервера по имени).

lua_shared_dict

синтаксис: lua_shared_dict <name> <size>

значение по умолчанию: нет

контекст: http

фаза: зависит от использования

Объявляет зону разделяемой памяти <name> для хранения Lua-словаря на основе shm ngx.shared.<name>.

Зоны разделяемой памяти всегда доступны всем рабочим процессам Nginx в текущем экземпляре сервера Nginx.

Аргумент <size> принимает единицы измерения размера, например k и m:

http {
    lua_shared_dict dogs 10m;
    ...
}

Жестко заданный минимальный размер составляет 8 КБ, тогда как практический минимальный размер зависит от фактического набора пользовательских данных (некоторые начинают с 12 КБ).

Подробности см. в разделе ngx.shared.DICT.

Эта директива впервые появилась в выпуске v0.3.1rc22.

lua_socket_connect_timeout

синтаксис: lua_socket_connect_timeout <time>

значение по умолчанию: lua_socket_connect_timeout 60s

контекст: http, server, location

Эта директива задает значение тайм-аута по умолчанию для метода connect объекта TCP-сокета или сокета домена Unix. Это значение можно переопределить методами settimeout или settimeouts.

Аргумент <time> может быть целым числом с необязательной единицей времени, например s (секунда), ms (миллисекунда), m (минута). Единица времени по умолчанию — s, то есть «секунда». Значение по умолчанию — 60s.

Эта директива впервые появилась в выпуске v0.5.0rc1.

lua_socket_send_timeout

синтаксис: lua_socket_send_timeout <time>

значение по умолчанию: lua_socket_send_timeout 60s

контекст: http, server, location

Задает значение тайм-аута по умолчанию для метода send объекта TCP-сокета или сокета домена Unix. Это значение можно переопределить методами settimeout или settimeouts.

Аргумент <time> может быть целым числом с необязательной единицей времени, например s (секунда), ms (миллисекунда), m (минута). Единица времени по умолчанию — s, то есть «секунда». Значение по умолчанию — 60s.

Эта директива впервые появилась в выпуске v0.5.0rc1.

lua_socket_send_lowat

синтаксис: lua_socket_send_lowat <size>

значение по умолчанию: lua_socket_send_lowat 0

контекст: http, server, location

Задает значение lowat (нижний порог) для буфера отправки cosocket.

lua_socket_read_timeout

синтаксис: lua_socket_read_timeout <time>

значение по умолчанию: lua_socket_read_timeout 60s

контекст: http, server, location

фаза: зависит от использования

Эта директива задает значение тайм-аута по умолчанию для метода receive объекта TCP-сокета или сокета домена Unix, а также для функций-итераторов, возвращаемых методом receiveuntil. Это значение можно переопределить методами settimeout или settimeouts.

Аргумент <time> может быть целым числом с необязательной единицей времени, например s (секунда), ms (миллисекунда), m (минута). Единица времени по умолчанию — s, то есть «секунда». Значение по умолчанию — 60s.

Эта директива впервые появилась в выпуске v0.5.0rc1.

lua_socket_buffer_size

синтаксис: lua_socket_buffer_size <size>

значение по умолчанию: lua_socket_buffer_size 4k/8k

контекст: http, server, location

Задает размер буфера, используемого операциями чтения cosocket.

Буфер не обязательно должен быть настолько большим, чтобы одновременно вмещать все данные, поскольку cosocket поддерживает полностью небуферизованное чтение и разбор данных. Поэтому размер буфера даже в 1 байт должен работать повсюду, однако производительность может быть очень низкой.

Эта директива впервые появилась в выпуске v0.5.0rc1.

lua_socket_pool_size

синтаксис: lua_socket_pool_size <size>

значение по умолчанию: lua_socket_pool_size 30

контекст: http, server, location

Задает предельный размер (по количеству соединений) каждого пула соединений cosocket, связанного с каждым удаленным сервером (то есть определяемого парой «хост — порт» или путем к файлу сокета домена Unix).

По умолчанию в каждом пуле допускается 30 соединений.

Когда число соединений в пуле превышает установленный предел, закрывается наименее недавно использовавшееся (простаивающее) соединение, чтобы освободить место для текущего соединения.

Обратите внимание, что пул соединений cosocket создается для каждого рабочего процесса Nginx, а не для каждого экземпляра сервера Nginx, поэтому заданный здесь предел действует для каждого отдельного рабочего процесса Nginx.

Эта директива впервые появилась в выпуске v0.5.0rc1.

lua_socket_keepalive_timeout

синтаксис: lua_socket_keepalive_timeout <time>

значение по умолчанию: lua_socket_keepalive_timeout 60s

контекст: http, server, location

Эта директива задает максимальное время простоя по умолчанию для соединений во встроенном пуле соединений cosocket. По истечении этого времени простаивающие соединения будут закрыты и удалены из пула. Это значение можно переопределить методом setkeepalive объектов cosocket.

Аргумент <time> может быть целым числом с необязательной единицей времени, например s (секунда), ms (миллисекунда), m (минута). Единица времени по умолчанию — s, то есть «секунда». Значение по умолчанию — 60s.

Эта директива впервые появилась в выпуске v0.5.0rc1.

lua_socket_log_errors

синтаксис: lua_socket_log_errors on|off

значение по умолчанию: lua_socket_log_errors on

контекст: http, server, location

Эта директива позволяет включать и отключать регистрацию ошибок при сбоях TCP- или UDP-cosocket. Если в коде Lua уже предусмотрена надлежащая обработка ошибок и их регистрация, рекомендуется отключить эту директиву, чтобы предотвратить переполнение файлов журнала ошибок Nginx (обычно это довольно затратная операция).

Эта директива впервые появилась в выпуске v0.5.13.

lua_ssl_ciphers

синтаксис: lua_ssl_ciphers <ciphers>

значение по умолчанию: lua_ssl_ciphers DEFAULT

контекст: http, server, location

Задает список разрешенных шифров для запросов к серверу SSL/TLS в методе tcpsock:sslhandshake. Шифры указываются в формате, который понимает библиотека OpenSSL.

Полный список можно просмотреть с помощью команды «openssl ciphers».

Эта директива впервые появилась в выпуске v0.9.11.

lua_ssl_crl

синтаксис: lua_ssl_crl <file>

значение по умолчанию: нет

контекст: http, server, location

Указывает файл со списком отозванных сертификатов (CRL) в формате PEM, который используется для проверки сертификата сервера SSL/TLS в методе tcpsock:sslhandshake.

Эта директива впервые появилась в выпуске v0.9.11.

lua_ssl_protocols

синтаксис: lua_ssl_protocols [SSLv2] [SSLv3] [TLSv1] [TLSv1.1] [TLSv1.2] [TLSv1.3]

значение по умолчанию: lua_ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3

контекст: http, server, location

Включает указанные протоколы для запросов к серверу SSL/TLS в методе tcpsock:sslhandshake.

Поддержка параметра TLSv1.3 требует версии v0.10.12 и OpenSSL 1.1.1. Начиная с версии v0.10.25 значение по умолчанию изменено с SSLV3 TLSv1 TLSv1.1 TLSv1.2 на TLSv1 TLSv1.1 TLSv1.2 TLSv1.3.

Эта директива впервые появилась в выпуске v0.9.11.

lua_ssl_certificate

синтаксис: lua_ssl_certificate <file>

значение по умолчанию: none

контекст: http, server, location

Указывает путь к файлу сертификата SSL/TLS в формате PEM, используемого методом tcpsock:sslhandshake.

Эта директива позволяет указать сертификат SSL/TLS, который будет предъявлен серверу в процессе рукопожатия SSL/TLS.

Эта директива впервые появилась в выпуске v0.10.26.

См. также lua_ssl_certificate_key и lua_ssl_verify_depth.

lua_ssl_certificate_key

синтаксис: lua_ssl_certificate_key <file>

значение по умолчанию: none

контекст: http, server, location

Указывает путь к файлу закрытого ключа, связанного с сертификатом SSL/TLS, используемого методом tcpsock:sslhandshake.

Эта директива позволяет указать файл закрытого ключа, соответствующий сертификату SSL/TLS, заданному директивой lua_ssl_certificate. Закрытый ключ должен быть в формате PEM и соответствовать сертификату.

Эта директива впервые появилась в выпуске v0.10.26.

См. также lua_ssl_certificate и lua_ssl_verify_depth.

lua_ssl_trusted_certificate

синтаксис: lua_ssl_trusted_certificate <file>

значение по умолчанию: none

контекст: http, server, location

Указывает путь к файлу с доверенными сертификатами центров сертификации в формате PEM, которые используются для проверки сертификата сервера SSL/TLS методом tcpsock:sslhandshake.

Эта директива впервые появилась в выпуске v0.9.11.

См. также lua_ssl_verify_depth.

lua_ssl_verify_depth

синтаксис: lua_ssl_verify_depth <number>

значение по умолчанию: lua_ssl_verify_depth 1

контекст: http, server, location

Задает глубину проверки цепочки сертификатов сервера.

Эта директива впервые появилась в выпуске v0.9.11.

См. также lua_ssl_certificate, lua_ssl_certificate_key и lua_ssl_trusted_certificate.

lua_ssl_conf_command

синтаксис: lua_ssl_conf_command <command>

значение по умолчанию: no

контекст: http, server, location

Задает произвольные команды конфигурации OpenSSL.

Директива поддерживается при использовании OpenSSL версии 1.0.2 или выше и nginx версии 1.19.4 или выше. В зависимости от указанной команды может потребоваться более новая версия OpenSSL.

На одном уровне можно указать несколько директив lua_ssl_conf_command:

lua_ssl_conf_command Options PrioritizeChaCha;
lua_ssl_conf_command Ciphersuites TLS_CHACHA20_POLY1305_SHA256;

Команды конфигурации применяются после собственной настройки SSL в OpenResty, поэтому с их помощью можно переопределить любые параметры, заданные OpenResty.

Однако следует учитывать, что непосредственная настройка OpenSSL с помощью lua_ssl_conf_command может привести к поведению, не предусмотренному OpenResty, поэтому выполнять ее следует осторожно.

Эта директива впервые появилась в выпуске v0.10.21.

lua_http10_buffering

синтаксис: lua_http10_buffering on|off

значение по умолчанию: lua_http10_buffering on

контекст: http, server, location, location-if

Включает или отключает автоматическую буферизацию ответов на запросы HTTP 1.0 (или более ранних версий). Этот механизм буферизации используется главным образом для keep-alive в HTTP 1.0, который требует корректного заголовка ответа Content-Length.

Если код Lua явно задает заголовок ответа Content-Length до отправки заголовков (явно с помощью ngx.send_headers или неявно при первом вызове ngx.say или ngx.print), буферизация ответа HTTP 1.0 будет отключена, даже если эта директива включена.

Чтобы передавать очень большие ответы потоковым способом (например, с помощью вызова ngx.flush), эту директиву НЕОБХОДИМО отключить, чтобы минимизировать использование памяти.

По умолчанию эта директива on.

Эта директива впервые появилась в выпуске v0.5.0rc19.

rewrite_by_lua_no_postpone

синтаксис: rewrite_by_lua_no_postpone on|off

значение по умолчанию: rewrite_by_lua_no_postpone off

контекст: http

Управляет отключением отложенного выполнения директив rewrite_by_lua* до конца фазы обработки запроса rewrite. По умолчанию эта директива отключена, а выполнение кода Lua откладывается до конца фазы rewrite.

Эта директива впервые появилась в выпуске v0.5.0rc29.

access_by_lua_no_postpone

синтаксис: access_by_lua_no_postpone on|off

значение по умолчанию: access_by_lua_no_postpone off

контекст: http

Управляет отключением отложенного выполнения директив access_by_lua* до конца фазы обработки запроса access. По умолчанию эта директива отключена, а выполнение кода Lua откладывается до конца фазы access.

Эта директива впервые появилась в выпуске v0.9.20.

lua_transform_underscores_in_response_headers

синтаксис: lua_transform_underscores_in_response_headers on|off

значение по умолчанию: lua_transform_underscores_in_response_headers on

контекст: http, server, location, location-if

Управляет преобразованием символов подчеркивания (_) в именах заголовков ответа, заданных через API ngx.header.HEADER, в дефисы (-).

Эта директива впервые появилась в выпуске v0.5.0rc32.

lua_check_client_abort

синтаксис: lua_check_client_abort on|off

значение по умолчанию: lua_check_client_abort off

контекст: http, server, location, location-if

Эта директива управляет проверкой преждевременного разрыва соединения клиентом.

Если эта директива включена, модуль ngx_lua отслеживает события преждевременного закрытия соединения на нисходящих соединениях. При возникновении такого события он вызывает пользовательскую функцию обратного вызова Lua (зарегистрированную с помощью ngx.on_abort) или просто останавливает и очищает все работающие «легкие потоки» Lua в обработчике текущего запроса, если пользовательская функция обратного вызова не зарегистрирована.

Однако, согласно текущей реализации, если клиент закрывает соединение до того, как код Lua завершает чтение данных тела запроса с помощью ngx.req.socket, ngx_lua не остановит работающие «легкие потоки» и не вызовет пользовательскую функцию обратного вызова (если была вызвана ngx.on_abort). Вместо этого операция чтения через ngx.req.socket просто вернет сообщение об ошибке "client aborted" в качестве второго возвращаемого значения (первым возвращаемым значением гарантированно будет nil).

При отключенном TCP keepalive предполагается, что клиент корректно закроет сокет (отправив пакет FIN или что-то подобное). Для (условно) работающих в реальном времени веб-приложений настоятельно рекомендуется настроить поддержку TCP keepalive в реализации стека TCP вашей системы, чтобы своевременно обнаруживать «полуоткрытые» TCP-соединения.

Например, в Linux стандартную директиву listen в файле nginx.conf можно настроить следующим образом:

listen 80 so_keepalive=2s:2s:8;

В FreeBSD можно настроить только системные параметры TCP keepalive, например:

# sysctl net.inet.tcp.keepintvl=2000
# sysctl net.inet.tcp.keepidle=2000

Эта директива впервые появилась в выпуске v0.7.4.

См. также ngx.on_abort.

lua_max_pending_timers

синтаксис: lua_max_pending_timers <count>

значение по умолчанию: lua_max_pending_timers 1024

контекст: http

Задает максимальное количество ожидающих таймеров.

Ожидающие таймеры — это таймеры, срок действия которых еще не истек.

При превышении этого предела вызов ngx.timer.at немедленно вернет nil и строку ошибки "too many pending timers".

Эта директива впервые появилась в выпуске v0.8.0.

lua_max_running_timers

синтаксис: lua_max_running_timers <count>

значение по умолчанию: lua_max_running_timers 256

контекст: http

Задает максимальное количество «работающих таймеров».

Работающие таймеры — это таймеры, пользовательские функции обратного вызова которых еще выполняются, либо lightthreads, порожденные в функциях обратного вызова, все еще выполняются.

При превышении этого предела Nginx прекратит выполнение функций обратного вызова недавно сработавших таймеров и запишет сообщение об ошибке "N lua_max_running_timers are not enough", где "N" — текущее значение этой директивы.

Эта директива впервые появилась в выпуске v0.8.0.

lua_sa_restart

синтаксис: lua_sa_restart on|off

значение по умолчанию: lua_sa_restart on

контекст: http

Если эта директива включена, модуль установит флаг SA_RESTART для параметров обработки сигналов рабочих процессов Nginx.

Это позволяет примитивам ввода-вывода Lua не прерываться при обработке Nginx различных сигналов.

Эта директива впервые появилась в выпуске v0.10.14.

lua_worker_thread_vm_pool_size

синтаксис: lua_worker_thread_vm_pool_size <size>

значение по умолчанию: lua_worker_thread_vm_pool_size 10

контекст: http

Задает ограничение размера пула виртуальных машин Lua (по умолчанию 100), используемого API ngx.run_worker_thread.

Также запрещено создавать виртуальные машины Lua, если их число превышает ограничение размера пула.

Виртуальная машина Lua из пула используется для выполнения кода Lua в отдельном потоке.

Пул является глобальным для рабочего процесса Nginx и используется для повторного использования виртуальных машин Lua между запросами.

Предупреждение: Каждый рабочий поток использует отдельную виртуальную машину Lua и сохраняет ее для повторного использования при последующих операциях. Слишком большое количество рабочих потоков может привести к значительному расходу памяти.

API Nginx для Lua

  • Введение
  • ngx.arg
  • ngx.var.VARIABLE
  • Основные константы
  • Константы методов HTTP
  • Константы статусов HTTP
  • Константы уровней журналирования Nginx
  • print
  • ngx.ctx
  • ngx.location.capture
  • ngx.location.capture_multi
  • ngx.status
  • ngx.header.HEADER
  • ngx.resp.get_headers
  • ngx.req.is_internal
  • ngx.req.start_time
  • ngx.req.http_version
  • ngx.req.raw_header
  • ngx.req.get_method
  • ngx.req.set_method
  • ngx.req.set_uri
  • ngx.req.set_uri_args
  • ngx.req.get_uri_args
  • ngx.req.get_post_args
  • ngx.req.get_headers
  • ngx.req.set_header
  • ngx.req.clear_header
  • ngx.req.read_body
  • ngx.req.discard_body
  • ngx.req.get_body_data
  • ngx.req.get_body_file
  • ngx.req.set_body_data
  • ngx.req.set_body_file
  • ngx.req.init_body
  • ngx.req.append_body
  • ngx.req.finish_body
  • ngx.req.socket
  • ngx.exec
  • ngx.redirect
  • ngx.send_headers
  • ngx.headers_sent
  • ngx.print
  • ngx.say
  • ngx.log
  • ngx.flush
  • ngx.exit
  • ngx.eof
  • ngx.sleep
  • ngx.escape_uri
  • ngx.unescape_uri
  • ngx.encode_args
  • ngx.decode_args
  • ngx.encode_base64
  • ngx.decode_base64
  • ngx.decode_base64mime
  • ngx.crc32_short
  • ngx.crc32_long
  • ngx.hmac_sha1
  • ngx.md5
  • ngx.md5_bin
  • ngx.sha1_bin
  • ngx.quote_sql_str
  • ngx.today
  • ngx.time
  • ngx.now
  • ngx.update_time
  • ngx.localtime
  • ngx.utctime
  • ngx.cookie_time
  • ngx.http_time
  • ngx.parse_http_time
  • ngx.is_subrequest
  • ngx.re.match
  • ngx.re.find
  • ngx.re.gmatch
  • ngx.re.sub
  • ngx.re.gsub
  • ngx.shared.DICT
  • ngx.shared.DICT.get
  • ngx.shared.DICT.get_stale
  • ngx.shared.DICT.set
  • ngx.shared.DICT.safe_set
  • ngx.shared.DICT.add
  • ngx.shared.DICT.safe_add
  • ngx.shared.DICT.replace
  • ngx.shared.DICT.delete
  • ngx.shared.DICT.incr
  • ngx.shared.DICT.lpush
  • ngx.shared.DICT.rpush
  • ngx.shared.DICT.lpop
  • ngx.shared.DICT.rpop
  • ngx.shared.DICT.llen
  • ngx.shared.DICT.ttl
  • ngx.shared.DICT.expire
  • ngx.shared.DICT.flush_all
  • ngx.shared.DICT.flush_expired
  • ngx.shared.DICT.get_keys
  • ngx.shared.DICT.capacity
  • ngx.shared.DICT.free_space
  • ngx.socket.udp
  • udpsock:bind
  • udpsock:setpeername
  • udpsock:send
  • udpsock:receive
  • udpsock:close
  • udpsock:settimeout
  • ngx.socket.stream
  • ngx.socket.tcp
  • tcpsock:bind
  • tcpsock:connect
  • tcpsock:setclientcert
  • tcpsock:sslhandshake
  • tcpsock:send
  • tcpsock:receive
  • tcpsock:receiveany
  • tcpsock:receiveuntil
  • tcpsock:close
  • tcpsock:settimeout
  • tcpsock:settimeouts
  • tcpsock:setoption
  • tcpsock:setkeepalive
  • tcpsock:getreusedtimes
  • ngx.socket.connect
  • ngx.get_phase
  • ngx.thread.spawn
  • ngx.thread.wait
  • ngx.thread.kill
  • ngx.on_abort
  • ngx.timer.at
  • ngx.timer.every
  • ngx.timer.running_count
  • ngx.timer.pending_count
  • ngx.config.subsystem
  • ngx.config.debug
  • ngx.config.prefix
  • ngx.config.nginx_version
  • ngx.config.nginx_configure
  • ngx.config.ngx_lua_version
  • ngx.worker.exiting
  • ngx.worker.pid
  • ngx.worker.pids
  • ngx.worker.count
  • ngx.worker.id
  • ngx.semaphore
  • ngx.balancer
  • ngx.ssl
  • ngx.ocsp
  • ndk.set_var.DIRECTIVE
  • coroutine.create
  • coroutine.resume
  • coroutine.yield
  • coroutine.wrap
  • coroutine.running
  • coroutine.status
  • ngx.run_worker_thread

Введение

Различные директивы конфигурации *_by_lua, *_by_lua_block и *_by_lua_file служат точками доступа к API Lua в файле nginx.conf. Описанный ниже API Nginx для Lua можно вызывать только из пользовательского кода Lua, выполняемого в контексте этих директив конфигурации.

API предоставляется Lua в виде двух стандартных пакетов ngx и ndk. Эти пакеты находятся в глобальной области видимости по умолчанию в ngx_lua и всегда доступны в директивах ngx_lua.

Подключить пакеты во внешние модули Lua можно следующим образом:

local say = ngx.say

local _M = {}

function _M.foo(a)
    say(a)
end

return _M

Настоятельно не рекомендуется использовать флаг package.seeall из-за различных нежелательных побочных эффектов.

Кроме того, пакеты можно напрямую подключать во внешних модулях Lua:

local ngx = require "ngx"
local ndk = require "ndk"

Возможность подключать эти пакеты появилась в выпуске v0.2.1rc19.

Операции сетевого ввода-вывода в пользовательском коде следует выполнять только с помощью вызовов API Nginx для Lua, поскольку в противном случае может блокироваться цикл событий Nginx и резко снижаться производительность. Операции с диском и относительно небольшими объемами данных можно выполнять с помощью стандартной библиотеки Lua io, но по возможности следует избегать чтения и записи больших файлов, поскольку это может значительно блокировать процесс Nginx. Для достижения максимальной производительности настоятельно рекомендуется передавать все операции сетевого и дискового ввода-вывода подзапросам Nginx (с помощью метода ngx.location.capture и аналогичных методов).

ngx.arg

синтаксис: val = ngx.arg[index]

контекст: set_by_lua*, body_filter_by_lua*

При использовании в контексте директив set_by_lua* эта таблица доступна только для чтения и содержит входные аргументы директив конфигурации:

value = ngx.arg[n]

Вот пример

location /foo {
    set $a 32;
    set $b 56;

    set_by_lua $sum
        'return tonumber(ngx.arg[1]) + tonumber(ngx.arg[2])'
        $a $b;

    echo $sum;
}

который выводит 88 — сумму 32 и 56.

При использовании этой таблицы в контексте body_filter_by_lua* первый элемент содержит входной блок данных для кода выходного фильтра, а второй элемент — логический флаг "eof", обозначающий конец всего потока выходных данных.

Блок данных и флаг "eof", передаваемые нижестоящим выходным фильтрам Nginx, также можно переопределить, присвоив значения соответствующим элементам таблицы. Если присвоить nil или пустую строку Lua значению ngx.arg[1], нижестоящим выходным фильтрам Nginx не будет передан блок данных.

ngx.var.VARIABLE

синтаксис: ngx.var.VAR_NAME

контекст: set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, balancer_by_lua*

Чтение и запись значений переменных Nginx.

value = ngx.var.some_nginx_variable_name
ngx.var.some_nginx_variable_name = value

Обратите внимание, что записывать можно только уже определенные переменные Nginx. Например:

location /foo {
    set $my_var ''; # this line is required to create $my_var at config time
    content_by_lua_block {
        ngx.var.my_var = 123
        ...
    }
}

Иными словами, переменные Nginx нельзя создавать на лету. Список предопределенных переменных Nginx приведен здесь.

Некоторым специальным переменным Nginx, например $args и $limit_rate, можно присваивать значения, а многим другим, например $query_string, $arg_PARAMETER и $http_NAME, — нельзя.

Этим интерфейсом также можно читать переменные захвата групп регулярного выражения Nginx $1, $2 и $3 и т. д., используя ngx.var[1], ngx.var[2], ngx.var[3] и т. д.

Присваивание ngx.var.Foo значения nil отменит установку переменной Nginx $Foo.

ngx.var.args = nil

ВНИМАНИЕ При чтении переменной Nginx Nginx выделяет память в пуле памяти запроса, которая освобождается только при завершении запроса. Поэтому, если в коде Lua требуется многократно читать переменную Nginx, сохраните ее значение в собственной переменной Lua, например:

local val = ngx.var.some_var
--- use the val repeatedly later

Это предотвращает (временную) утечку памяти в течение текущего запроса. Еще один способ кэширования результата — использовать таблицу ngx.ctx.

Неопределенные переменные Nginx при вычислении дают nil, а неинициализированные (но определенные) переменные Nginx дают пустую строку Lua.

Этот API требует относительно затратного вызова метаметода, поэтому рекомендуется не использовать его в критичных к производительности участках кода.

Основные константы

контекст: init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, *log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, ssl_client_hello_by_lua*

ngx.OK (0)
ngx.ERROR (-1)
ngx.AGAIN (-2)
ngx.DONE (-4)
ngx.DECLINED (-5)

Обратите внимание, что API Nginx для Lua использует только три из этих констант (например, ngx.exit принимает ngx.OK, ngx.ERROR и ngx.DECLINED в качестве входных значений).

ngx.null

Константа ngx.null — это NULL light userdata, обычно используемая для представления значений nil в таблицах Lua и т. п.; она аналогична константе cjson.null библиотеки lua-cjson. Эта константа впервые появилась в выпуске v0.5.0rc5.

Константа ngx.DECLINED впервые появилась в выпуске v0.5.0rc19.

Константы методов HTTP

контекст: init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, ssl_client_hello_by_lua*

  ngx.HTTP_GET
  ngx.HTTP_HEAD
  ngx.HTTP_PUT
  ngx.HTTP_POST
  ngx.HTTP_DELETE
  ngx.HTTP_OPTIONS   (added in the v0.5.0rc24 release)
  ngx.HTTP_MKCOL     (added in the v0.8.2 release)
  ngx.HTTP_COPY      (added in the v0.8.2 release)
  ngx.HTTP_MOVE      (added in the v0.8.2 release)
  ngx.HTTP_PROPFIND  (added in the v0.8.2 release)
  ngx.HTTP_PROPPATCH (added in the v0.8.2 release)
  ngx.HTTP_LOCK      (added in the v0.8.2 release)
  ngx.HTTP_UNLOCK    (added in the v0.8.2 release)
  ngx.HTTP_PATCH     (added in the v0.8.2 release)
  ngx.HTTP_TRACE     (added in the v0.8.2 release)

Эти константы обычно используются при вызове методов ngx.location.capture и ngx.location.capture_multi.

Константы статусов HTTP

контекст: init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, ssl_client_hello_by_lua*

value = ngx.HTTP_CONTINUE (100) (first added in the v0.9.20 release)
value = ngx.HTTP_SWITCHING_PROTOCOLS (101) (first added in the v0.9.20 release)
value = ngx.HTTP_OK (200)
value = ngx.HTTP_CREATED (201)
value = ngx.HTTP_ACCEPTED (202) (first added in the v0.9.20 release)
value = ngx.HTTP_NO_CONTENT (204) (first added in the v0.9.20 release)
value = ngx.HTTP_PARTIAL_CONTENT (206) (first added in the v0.9.20 release)
value = ngx.HTTP_SPECIAL_RESPONSE (300)
value = ngx.HTTP_MOVED_PERMANENTLY (301)
value = ngx.HTTP_MOVED_TEMPORARILY (302)
value = ngx.HTTP_SEE_OTHER (303)
value = ngx.HTTP_NOT_MODIFIED (304)
value = ngx.HTTP_TEMPORARY_REDIRECT (307) (first added in the v0.9.20 release)
value = ngx.HTTP_PERMANENT_REDIRECT (308)
value = ngx.HTTP_BAD_REQUEST (400)
value = ngx.HTTP_UNAUTHORIZED (401)
value = ngx.HTTP_PAYMENT_REQUIRED (402) (first added in the v0.9.20 release)
value = ngx.HTTP_FORBIDDEN (403)
value = ngx.HTTP_NOT_FOUND (404)
value = ngx.HTTP_NOT_ALLOWED (405)
value = ngx.HTTP_NOT_ACCEPTABLE (406) (first added in the v0.9.20 release)
value = ngx.HTTP_REQUEST_TIMEOUT (408) (first added in the v0.9.20 release)
value = ngx.HTTP_CONFLICT (409) (first added in the v0.9.20 release)
value = ngx.HTTP_GONE (410)
value = ngx.HTTP_UPGRADE_REQUIRED (426) (first added in the v0.9.20 release)
value = ngx.HTTP_TOO_MANY_REQUESTS (429) (first added in the v0.9.20 release)
value = ngx.HTTP_CLOSE (444) (first added in the v0.9.20 release)
value = ngx.HTTP_ILLEGAL (451) (first added in the v0.9.20 release)
value = ngx.HTTP_INTERNAL_SERVER_ERROR (500)
value = ngx.HTTP_NOT_IMPLEMENTED (501)
value = ngx.HTTP_METHOD_NOT_IMPLEMENTED (501) (kept for compatibility)
value = ngx.HTTP_BAD_GATEWAY (502) (first added in the v0.9.20 release)
value = ngx.HTTP_SERVICE_UNAVAILABLE (503)
value = ngx.HTTP_GATEWAY_TIMEOUT (504) (first added in the v0.3.1rc38 release)
value = ngx.HTTP_VERSION_NOT_SUPPORTED (505) (first added in the v0.9.20 release)
value = ngx.HTTP_INSUFFICIENT_STORAGE (507) (first added in the v0.9.20 release)

Константы уровней логирования Nginx

контекст: init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, exit_worker_by_lua*, ssl_client_hello_by_lua*

ngx.STDERR
ngx.EMERG
ngx.ALERT
ngx.CRIT
ngx.ERR
ngx.WARN
ngx.NOTICE
ngx.INFO
ngx.DEBUG

Эти константы обычно используются методом ngx.log.

print

синтаксис: print(...)

контекст: init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, exit_worker_by_lua*, ssl_client_hello_by_lua*

Записывает значения аргументов в файл Nginx error.log с уровнем логирования ngx.NOTICE.

Эквивалентно следующему:

ngx.log(ngx.NOTICE, ...)

Аргументы Lua nil принимаются и преобразуются в строковые литералы "nil", а логические значения Lua — в строковые литералы "true" или "false". Константа ngx.null выводится как строка "null".

В ядре Nginx жестко задано ограничение 2048 байт на длину сообщений об ошибках. В это ограничение входят завершающие символы новой строки и начальные временные метки. Если размер сообщения превышает это ограничение, Nginx соответствующим образом обрежет его текст. Это ограничение можно изменить вручную, отредактировав определение макроса NGX_MAX_ERROR_STR в файле src/core/ngx_log.h в дереве исходного кода Nginx.

ngx.ctx

контекст: init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, exit_worker_by_lua*

Эту таблицу можно использовать для хранения данных контекста Lua, относящихся к отдельному запросу. Время ее жизни совпадает со временем жизни текущего запроса (как и у переменных Nginx).

Рассмотрим следующий пример:

location /test {
    rewrite_by_lua_block {
        ngx.ctx.foo = 76
    }
    access_by_lua_block {
        ngx.ctx.foo = ngx.ctx.foo + 3
    }
    content_by_lua_block {
        ngx.say(ngx.ctx.foo)
    }
}

Тогда GET /test выведет:

79

То есть запись ngx.ctx.foo сохраняется на этапах rewrite, access и content запроса.

У каждого запроса, включая подзапросы, есть собственная копия таблицы. Например:

location /sub {
    content_by_lua_block {
        ngx.say("sub pre: ", ngx.ctx.blah)
        ngx.ctx.blah = 32
        ngx.say("sub post: ", ngx.ctx.blah)
    }
}

location /main {
    content_by_lua_block {
        ngx.ctx.blah = 73
        ngx.say("main pre: ", ngx.ctx.blah)
        local res = ngx.location.capture("/sub")
        ngx.print(res.body)
        ngx.say("main post: ", ngx.ctx.blah)
    }
}

Тогда GET /main выведет:

main pre: 73
sub pre: nil
sub post: 32
main post: 73

В данном случае изменение записи ngx.ctx.blah в подзапросе не влияет на запись в родительском запросе. Это происходит потому, что у них две отдельные версии ngx.ctx.blah.

Внутренние перенаправления (инициируемые такими директивами конфигурации nginx, как error_page, try_files, index и т. д.) уничтожают исходные данные запроса ngx.ctx (если они есть), а новый запрос получает пустую таблицу ngx.ctx. Например:

location /new {
    content_by_lua_block {
        ngx.say(ngx.ctx.foo)
    }
}

location /orig {
    content_by_lua_block {
        ngx.ctx.foo = "hello"
        ngx.exec("/new")
    }
}

Тогда GET /orig выведет:

nil

а не исходное значение "hello".

Поскольку HTTP-запрос создается после SSL-рукопожатия, объект ngx.ctx, созданный в ssl_certificate_by_lua*, ssl_session_store_by_lua*, ssl_session_fetch_by_lua* и ssl_client_hello_by_lua*, недоступен на последующих этапах, например в rewrite_by_lua*.

Начиная с v0.10.18, объект ngx.ctx, созданный во время SSL-рукопожатия, наследуется запросами, использующими одно и то же TCP-соединение, установленное во время рукопожатия. Обратите внимание: переопределение значений в ngx.ctx на этапах обработки HTTP-запроса (например, в rewrite_by_lua*) влияет только на текущий HTTP-запрос.

В эту «магическую» таблицу можно помещать произвольные значения, включая замыкания Lua и вложенные таблицы. Она также позволяет регистрировать пользовательские метаметоды.

Поддерживается и переопределение ngx.ctx новой таблицей Lua, например:

ngx.ctx = { foo = 32, bar = 54 }

При использовании в контексте init_worker_by_lua* время жизни этой таблицы совпадает со временем жизни текущего обработчика Lua.

Для обращения к ngx.ctx требуются относительно затратные вызовы метаметодов, поэтому это значительно медленнее, чем явная передача данных запроса через аргументы собственных функций. Не злоупотребляйте этим API для сохранения аргументов собственных функций, поскольку это обычно заметно снижает производительность.

Из-за магии метаметодов никогда не объявляйте таблицу ngx.ctx локальной за пределами области видимости функции Lua, на уровне модуля Lua, из-за совместного использования данных на уровне рабочего процесса. Например, следующий вариант неверен:

-- mymodule.lua
local _M = {}

-- the following line is bad since ngx.ctx is a per-request
-- data while this <code>ctx</code> variable is on the Lua module level
-- and thus is per-nginx-worker.
local ctx = ngx.ctx

function _M.main()
    ctx.foo = "bar"
end

return _M

Вместо этого используйте следующий вариант:

-- mymodule.lua
local _M = {}

function _M.main(ctx)
    ctx.foo = "bar"
end

return _M

То есть вызывающий код должен явно передавать таблицу ctx через аргумент функции.

ngx.location.capture

синтаксис: res = ngx.location.capture(uri, options?)

контекст: rewrite_by_lua*, access_by_lua*, content_by_lua*

Выполняет синхронный, но неблокирующий подзапрос Nginx с помощью uri.

Подзапросы Nginx предоставляют мощный способ выполнять неблокирующие внутренние запросы к другим location, настроенным для обслуживания файлов из каталога на диске, или к любым другим модулям Nginx на C, таким как ngx_proxy, ngx_fastcgi, ngx_memc, ngx_postgres, ngx_drizzle, включая сам ngx_lua, и многим другим.

Обратите также внимание: подзапросы лишь имитируют HTTP-интерфейс, но не создают дополнительный трафик HTTP/TCP и не используют IPC. Все операции выполняются внутри системы, эффективно и на уровне C.

Подзапросы принципиально отличаются от перенаправления HTTP 301/302 (с помощью ngx.redirect) и внутреннего перенаправления (с помощью ngx.exec).

Перед выполнением подзапроса всегда считывайте тело запроса (вызвав ngx.req.read_body или включив директиву lua_need_request_body).

Эта функция API (как и ngx.location.capture_multi) всегда буферизует в памяти все тело ответа подзапроса. Поэтому, если требуется обрабатывать большие ответы подзапросов, используйте вместо этого cosockets и потоковую обработку.

Вот простой пример:

res = ngx.location.capture(uri)

Возвращает таблицу Lua с 4 элементами: res.status, res.header, res.body и res.truncated.

res.status содержит код состояния ответа подзапроса.

res.header содержит все заголовки ответа подзапроса и представляет собой обычную таблицу Lua. Для заголовков ответа с несколькими значениями используется таблица-массив Lua, содержащая все значения в порядке их появления. Например, если заголовки ответа подзапроса содержат следующие строки:

Set-Cookie: a=3
Set-Cookie: foo=bar
Set-Cookie: baz=blah

то res.header["Set-Cookie"] будет иметь значение-таблицу {"a=3", "foo=bar", "baz=blah"}.

res.body содержит данные тела ответа подзапроса, которые могут быть усечены. Всегда проверяйте логический флаг res.truncated, чтобы определить, содержит ли res.body усеченные данные. Усечение данных может быть вызвано только невосстановимыми ошибками в подзапросах, например преждевременным разрывом соединения удаленной стороной в середине потока данных тела ответа или тайм-аутом чтения при получении тела ответа от удаленной стороны.

Строки запроса URI можно добавлять непосредственно к URI, например:

res = ngx.location.capture('/foo/bar?a=3&b=4')

Именованные location, такие как @foo, запрещены из-за ограничения ядра Nginx. Используйте обычные location вместе с директивой internal, чтобы подготовить location, доступные только внутри системы.

Вторым аргументом можно передать необязательную таблицу параметров, поддерживающую следующие параметры:

  • method задает метод запроса подзапроса; допускаются только константы, такие как ngx.HTTP_POST.
  • body задает тело запроса подзапроса (только строковое значение).
  • args задает аргументы запроса URI подзапроса (принимаются как строковые значения, так и таблицы Lua).
  • headers задает заголовки запроса подзапроса (только таблица Lua). Эти заголовки заменяют исходные заголовки подзапроса.
  • ctx задает таблицу Lua, которая будет таблицей ngx.ctx для подзапроса. Ею может быть таблица ngx.ctx текущего запроса; в этом случае родительский запрос и его подзапрос будут использовать одну и ту же таблицу контекста. Этот параметр впервые появился в выпуске v0.3.1rc25.
  • vars принимает таблицу Lua со значениями, которые следует присвоить указанным переменным Nginx в подзапросе. Этот параметр впервые появился в выпуске v0.3.1rc31.
  • copy_all_vars указывает, следует ли копировать все значения переменных Nginx из текущего запроса в данный подзапрос. Изменение переменных Nginx в подзапросе не повлияет на текущий (родительский) запрос. Этот параметр впервые появился в выпуске v0.3.1rc31.
  • share_all_vars указывает, следует ли совместно использовать все переменные Nginx подзапроса с текущим (родительским) запросом. Изменения переменных Nginx в подзапросе повлияют на текущий (родительский) запрос. Включение этого параметра может привести к трудноотлаживаемым проблемам из-за нежелательных побочных эффектов и считается плохой практикой. Включайте его, только если полностью понимаете, что делаете.
  • always_forward_body если задано значение true, тело запроса текущего (родительского) запроса всегда будет передаваться создаваемому подзапросу, если не указан параметр body. Тело запроса, прочитанное с помощью ngx.req.read_body() или директивы lua_need_request_body on, будет передано непосредственно подзапросу без копирования всех данных тела запроса при создании подзапроса (независимо от того, буферизованы ли данные тела запроса в памяти или во временных файлах). По умолчанию этот параметр имеет значение false; если параметр body не указан, тело запроса текущего (родительского) запроса передается только в том случае, если подзапрос использует метод запроса PUT или POST.

Например, POST-подзапрос можно выполнить следующим образом:

res = ngx.location.capture(
    '/foo/bar',
    { method = ngx.HTTP_POST, body = 'hello, world' }
)

Методы, отличные от POST, см. в разделе о константах методов HTTP. По умолчанию параметр method имеет значение ngx.HTTP_GET.

Параметр args позволяет задать дополнительные аргументы URI, например:

ngx.location.capture('/foo?a=1',
    { args = { b = 3, c = ':' } }
)

эквивалентно следующему:

ngx.location.capture('/foo?a=1&b=3&c=%3a')

то есть этот метод экранирует ключи и значения аргументов согласно правилам URI и объединяет их в полную строку запроса. Формат таблицы Lua, передаваемой в качестве аргумента args, совпадает с форматом, используемым методом ngx.encode_args.

Параметр args также может принимать обычные строки запроса:

ngx.location.capture('/foo?a=1',
    { args = 'b=3&c=%3a' }
)

Функционально это идентично предыдущим примерам.

Параметр share_all_vars управляет совместным использованием переменных Nginx текущим запросом и его подзапросами. Если для этого параметра задано значение true, текущий запрос и связанные с ним подзапросы используют одну область видимости переменных Nginx. Таким образом, изменения переменных Nginx, сделанные подзапросом, повлияют на текущий запрос.

Используйте этот параметр с осторожностью: совместное использование области видимости переменных может иметь неожиданные побочные эффекты. Обычно предпочтительнее параметры args, vars или copy_all_vars.

По умолчанию этот параметр имеет значение false.

location /other {
    set $dog "$dog world";
    echo "$uri dog: $dog";
}

location /lua {
    set $dog 'hello';
    content_by_lua_block {
        res = ngx.location.capture("/other",
            { share_all_vars = true })

        ngx.print(res.body)
        ngx.say(ngx.var.uri, ": ", ngx.var.dog)
    }
}

Обращение к location /lua выведет:

/other dog: hello world
/lua: hello world

Параметр copy_all_vars предоставляет подзапросам копию переменных Nginx родительского запроса при их создании. Изменения этих переменных, сделанные такими подзапросами, не повлияют на родительский запрос или другие подзапросы, использующие переменные родительского запроса.

location /other {
    set $dog "$dog world";
    echo "$uri dog: $dog";
}

location /lua {
    set $dog 'hello';
    content_by_lua_block {
        res = ngx.location.capture("/other",
            { copy_all_vars = true })

        ngx.print(res.body)
        ngx.say(ngx.var.uri, ": ", ngx.var.dog)
    }
}

Запрос GET /lua выведет:

/other dog: hello world
/lua: hello

Обратите внимание: если для обоих параметров share_all_vars и copy_all_vars задано значение true, приоритет имеет share_all_vars.

Помимо двух описанных выше параметров, с помощью параметра vars можно задать значения переменных в подзапросе. Эти переменные устанавливаются после обработки настроек совместного использования или копирования переменных. Это более эффективный способ передать определенные значения подзапросу, чем кодировать их в аргументах URL и декодировать в файле конфигурации Nginx.

location /other {
    content_by_lua_block {
        ngx.say("dog = ", ngx.var.dog)
        ngx.say("cat = ", ngx.var.cat)
    }
}

location /lua {
    set $dog '';
    set $cat '';
    content_by_lua_block {
        res = ngx.location.capture("/other",
            { vars = { dog = "hello", cat = 32 }})

        ngx.print(res.body)
    }
}

Обращение к /lua выведет:

dog = hello
cat = 32

Параметр headers позволяет задать заголовки запроса подзапроса. Значением этого параметра должна быть таблица Lua, в которой ключи — имена заголовков, а значения — значения заголовков. Например:

location /foo {
    content_by_lua_block {
        ngx.print(ngx.var.http_x_test)
    }
}

location /lua {
    content_by_lua_block {
        local res = ngx.location.capture("/foo", {
            headers = {
                ["X-Test"] = "aa",
            }
        })
        ngx.print(res.body)
    }
}

Обращение к /lua выведет:

aa

Параметр ctx позволяет указать пользовательскую таблицу Lua, которая будет использоваться в качестве таблицы ngx.ctx подзапроса.

location /sub {
    content_by_lua_block {
        ngx.ctx.foo = "bar";
    }
}
location /lua {
    content_by_lua_block {
        local ctx = {}
        res = ngx.location.capture("/sub", { ctx = ctx })

        ngx.say(ctx.foo)
        ngx.say(ngx.ctx.foo)
    }
}

В таком случае запрос GET /lua выведет:

bar
nil

Также с помощью параметра ctx можно использовать одну и ту же таблицу ngx.ctx для текущего (родительского) запроса и подзапроса:

location /sub {
    content_by_lua_block {
        ngx.ctx.foo = "bar"
    }
}
location /lua {
    content_by_lua_block {
        res = ngx.location.capture("/sub", { ctx = ngx.ctx })
        ngx.say(ngx.ctx.foo)
    }
}

Запрос GET /lua выведет:

bar

Обратите внимание: подзапросы, выполняемые с помощью ngx.location.capture, по умолчанию наследуют все заголовки запроса текущего запроса, что может привести к неожиданным побочным эффектам в ответах подзапросов. Например, при использовании стандартного модуля ngx_proxy для обработки подзапросов заголовок "Accept-Encoding: gzip" основного запроса может привести к сжатым ответам, которые невозможно корректно обработать в коде Lua. Чтобы игнорировать исходные заголовки запроса, установите для proxy_pass_request_headers значение off в location подзапросов.

Если параметр body не указан, а параметр always_forward_body имеет значение false (по умолчанию), подзапросы POST и PUT наследуют тела запроса родительского запроса (если они есть).

Для каждого основного запроса жестко задано максимальное количество подзапросов. В старых версиях Nginx ограничение составляло 50 одновременно выполняющихся подзапросов, а в более новых версиях Nginx, начиная с 1.9.5, это ограничение изменено и теперь ограничивает глубину рекурсивных подзапросов. При превышении ограничения в файл error.log добавляется следующее сообщение об ошибке:

[error] 13983#0: *1 subrequests cycle while processing "/uri"

При необходимости ограничение можно изменить вручную, отредактировав определение макроса NGX_HTTP_MAX_SUBREQUESTS в файле nginx/src/http/ngx_http_request.h в дереве исходного кода Nginx.

См. также ограничения на перехват запросов к location, настроенным с помощью директив подзапросов других модулей.

ngx.location.capture_multi

синтаксис: res1, res2, ... = ngx.location.capture_multi({ {uri, options?}, {uri, options?}, ... })

контекст: rewrite_by_lua*, access_by_lua*, content_by_lua*

Как и ngx.location.capture, но поддерживает одновременное выполнение нескольких подзапросов.

Эта функция выполняет несколько параллельных подзапросов, заданных входной таблицей, и возвращает результаты в том же порядке. Например:

res1, res2, res3 = ngx.location.capture_multi{
    { "/foo", { args = "a=3&b=4" } },
    { "/bar" },
    { "/baz", { method = ngx.HTTP_POST, body = "hello" } },
}

if res1.status == ngx.HTTP_OK then
    ...
end

if res2.body == "BLAH" then
    ...
end

Функция не вернется, пока не завершатся все подзапросы. Общее время выполнения равно времени выполнения самого длительного подзапроса, а не сумме времени выполнения всех подзапросов.

Если количество подзапросов заранее неизвестно, для запросов и ответов можно использовать таблицы Lua:

-- construct the requests table
local reqs = {}
table.insert(reqs, { "/mysql" })
table.insert(reqs, { "/postgres" })
table.insert(reqs, { "/redis" })
table.insert(reqs, { "/memcached" })

-- issue all the requests at once and wait until they all return
local resps = {
    ngx.location.capture_multi(reqs)
}

-- loop over the responses table
for i, resp in ipairs(resps) do
    -- process the response table "resp"
end

Функция ngx.location.capture — это особый случай этой функции. Логически ngx.location.capture можно реализовать следующим образом:

ngx.location.capture =
    function (uri, args)
        return ngx.location.capture_multi({ {uri, args} })
    end

См. также ограничения на перехват запросов к location, настроенным с помощью директив подзапросов других модулей.

ngx.status

контекст: set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*

Чтение и изменение статуса ответа текущего запроса. Это следует делать до отправки заголовков ответа.

ngx.status = ngx.HTTP_CREATED
status = ngx.status

Изменение ngx.status после отправки заголовков ответа не возымеет эффекта, но в файл журнала ошибок Nginx будет записано сообщение об ошибке:

attempt to set ngx.status after sending out response headers

ngx.header.HEADER

синтаксис: ngx.header.HEADER = VALUE

синтаксис: value = ngx.header.HEADER

контекст: rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*

Устанавливает, добавляет или удаляет заголовок ответа текущего запроса HEADER, который будет отправлен.

По умолчанию символы подчеркивания (_) в именах заголовков заменяются дефисами (-). Это преобразование можно отключить с помощью директивы lua_transform_underscores_in_response_headers.

Имена заголовков сравниваются без учета регистра.

-- equivalent to ngx.header["Content-Type"] = 'text/plain'
ngx.header.content_type = 'text/plain'

ngx.header["X-My-Header"] = 'blah blah'

Заголовки с несколькими значениями можно задать следующим образом:

ngx.header['Set-Cookie'] = {'a=32; path=/', 'b=4; path=/'}

что даст:

Set-Cookie: a=32; path=/
Set-Cookie: b=4; path=/

в заголовках ответа.

Принимаются только таблицы Lua (для стандартных заголовков, таких как Content-Type, допускающих только одно значение, действует только последний элемент таблицы).

ngx.header.content_type = {'a', 'b'}

эквивалентно следующему:

ngx.header.content_type = 'b'

Установка значения nil для элемента фактически удаляет его из заголовков ответа:

ngx.header["X-My-Header"] = nil

То же самое происходит при присваивании пустой таблицы:

ngx.header["X-My-Header"] = {}

Изменение ngx.header.HEADER после отправки заголовков ответа (явно с помощью ngx.send_headers или неявно с помощью ngx.print и подобных функций) приведет к записи сообщения об ошибке в журнал.

При чтении ngx.header.HEADER возвращается значение заголовка ответа с именем HEADER.

Символы подчеркивания (_) в именах заголовков также заменяются дефисами (-), а имена заголовков сравниваются без учета регистра. Если заголовок ответа отсутствует, возвращается nil.

Это особенно полезно в контексте header_filter_by_lua*, например:

location /test {
    set $footer '';

    proxy_pass http://some-backend;

    header_filter_by_lua_block {
        if ngx.header["X-My-Header"] == "blah" then
            ngx.var.footer = "some value"
        end
    }

    echo_after_body $footer;
}

Для заголовков с несколькими значениями все значения заголовка собираются по порядку и возвращаются в виде таблицы Lua. Например, заголовки ответа:

Foo: bar
Foo: baz

приведут к следующему результату:

{"bar", "baz"}

при чтении ngx.header.Foo.

Обратите внимание: ngx.header — это не обычная таблица Lua, поэтому перебрать ее с помощью функции Lua ipairs невозможно.

Примечание: эта функция выдает ошибку Lua, если HEADER или VALUE содержат небезопасные символы (управляющие символы).

Для чтения заголовков запроса используйте функцию ngx.req.get_headers.

ngx.resp.get_headers

синтаксис: headers, err = ngx.resp.get_headers(max_headers?, raw?)

контекст: set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, balancer_by_lua*

Возвращает таблицу Lua со всеми заголовками ответа текущего запроса.

local h, err = ngx.resp.get_headers()

if err == "truncated" then
    -- one can choose to ignore or reject the current response here
end

for k, v in pairs(h) do
    ...
end

Эта функция имеет ту же сигнатуру, что и ngx.req.get_headers, но получает заголовки ответа, а не запроса.

Обратите внимание: по умолчанию анализируется не более 100 заголовков ответа (включая заголовки с одинаковыми именами), а остальные заголовки ответа молча отбрасываются для защиты от потенциальных атак типа «отказ в обслуживании». Начиная с v0.10.13, при превышении лимита функция возвращает второе значение — строку "truncated".

Этот API впервые появился в выпуске v0.9.5.

ngx.req.is_internal

синтаксис: is_internal = ngx.req.is_internal()

контекст: set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*

Возвращает логическое значение, указывающее, является ли текущий запрос «внутренним запросом», то есть запросом, инициированным изнутри текущего сервера Nginx, а не со стороны клиента.

Все подзапросы являются внутренними запросами, как и запросы после внутренних перенаправлений.

Этот API впервые появился в выпуске v0.9.20.

ngx.req.start_time

синтаксис: secs = ngx.req.start_time()

контекст: set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*

Возвращает число с плавающей точкой, представляющее временную метку создания текущего запроса (дробная часть содержит миллисекунды).

Следующий пример на чистом Lua имитирует значение переменной $request_time (предоставляемой ngx_http_log_module):

local request_time = ngx.now() - ngx.req.start_time()

Эта функция впервые появилась в выпуске v0.7.7.

См. также ngx.now и ngx.update_time.

ngx.req.http_version

синтаксис: num = ngx.req.http_version()

контекст: set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*

Возвращает номер версии HTTP текущего запроса в виде числа Lua.

Возможные текущие значения: 3.0, 2.0, 1.0, 1.1 и 0.9. Для неизвестных значений возвращается nil.

Этот метод впервые появился в выпуске v0.7.17.

ngx.req.raw_header

синтаксис: str = ngx.req.raw_header(no_request_line?)

контекст: set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*

Возвращает исходный необработанный заголовок протокола HTTP, полученный сервером Nginx.

По умолчанию также включаются строка запроса и завершающий маркер CR LF. Например:

ngx.print(ngx.req.raw_header())

возвращает примерно следующее:

GET /t HTTP/1.1
Host: localhost
Connection: close
Foo: bar

Чтобы исключить строку запроса из результата, можно задать необязательный аргумент no_request_line со значением true. Например:

ngx.print(ngx.req.raw_header(true))

выведет примерно следующее:

Host: localhost
Connection: close
Foo: bar

Этот метод впервые появился в выпуске v0.7.17.

Этот метод пока не работает для запросов HTTP/2.

ngx.req.get_method

синтаксис: method_name = ngx.req.get_method()

контекст: set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, balancer_by_lua*, log_by_lua*

Получает название метода текущего запроса. Вместо числовых констант методов возвращаются строки, например "GET" и "POST".

Если текущий запрос является подзапросом Nginx, возвращается название метода подзапроса.

Этот метод впервые появился в выпуске v0.5.6.

См. также ngx.req.set_method.

ngx.req.set_method

синтаксис: ngx.req.set_method(method_id)

контекст: set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*

Переопределяет метод текущего запроса значением аргумента method_id. В настоящее время поддерживаются только числовые константы методов, например ngx.HTTP_POST и ngx.HTTP_GET.

Если текущий запрос является подзапросом Nginx, метод подзапроса будет переопределён.

Этот метод впервые появился в выпуске v0.5.6.

См. также ngx.req.get_method.

ngx.req.set_uri

синтаксис: ngx.req.set_uri(uri, jump?, binary?)

контекст: set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*

Перезаписывает (разобранный) URI текущего запроса значением аргумента uri. Аргумент uri должен быть строкой Lua ненулевой длины, иначе будет вызвано исключение Lua.

Необязательный аргумент jump типа boolean может вызвать повторный поиск location (или переход к другой location), как директива ngx_http_rewrite_module rewrite. Иными словами, если jump равно true (по умолчанию false), эта функция не вернёт управление и сообщит Nginx, что на более поздней фазе post-rewrite нужно повторно поискать location с новым значением URI и перейти к найденной location.

В противном случае переход к другой location не выполняется, а изменяется только URI текущего запроса; это также поведение по умолчанию. Функция вернёт управление без возвращаемых значений, если аргумент jump равен false или вовсе не указан.

Например, следующий фрагмент конфигурации Nginx

rewrite ^ /foo last;

можно записать на Lua так:

ngx.req.set_uri("/foo", true)

Аналогично, конфигурацию Nginx

rewrite ^ /foo break;

можно записать на Lua так:

ngx.req.set_uri("/foo", false)

или, что эквивалентно, так:

ngx.req.set_uri("/foo")

Аргумент jump может иметь значение true только в rewrite_by_lua*. Использовать jump в других контекстах запрещено — это вызовет исключение Lua.

Более сложный пример с подстановками регулярных выражений:

location /test {
    rewrite_by_lua_block {
        local uri = ngx.re.sub(ngx.var.uri, "^/test/(.*)", "/$1", "o")
        ngx.req.set_uri(uri)
    }
    proxy_pass http://my_backend;
}

функционально эквивалентен следующему:

location /test {
    rewrite ^/test/(.*) /$1 break;
    proxy_pass http://my_backend;
}

Примечание: эта функция вызывает ошибку Lua, если аргумент uri содержит небезопасные символы (управляющие символы).

Обратите внимание: с помощью этого интерфейса нельзя перезаписать аргументы URI; для этого следует использовать ngx.req.set_uri_args. Например, конфигурацию Nginx

rewrite ^ /foo?a=3? last;

можно записать так:

ngx.req.set_uri_args("a=3")
ngx.req.set_uri("/foo", true)

или так:

ngx.req.set_uri_args({a = 3})
ngx.req.set_uri("/foo", true)

Начиная с версии 0.10.16 этого модуля, функция принимает необязательный аргумент binary типа boolean, позволяющий использовать произвольные двоичные данные URI. По умолчанию аргумент binary имеет значение false, и функция вызовет ошибку Lua, как показано ниже, если аргумент uri содержит управляющие символы (коды ASCII от 0 до 0x08, от 0x0A до 0x1F и 0x7F).

[error] 23430#23430: *1 lua entry thread aborted: runtime error:
content_by_lua(nginx.conf:44):3: ngx.req.set_uri unsafe byte "0x00"
in "\x00foo" (maybe you want to set the 'binary' argument?)

Этот интерфейс впервые появился в выпуске v0.3.1rc14.

ngx.req.set_uri_args

синтаксис: ngx.req.set_uri_args(args)

контекст: set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*

Перезаписывает аргументы запроса URI текущего запроса значением аргумента args. Аргумент args может быть строкой Lua, например

ngx.req.set_uri_args("a=3&b=hello%20world")

или таблицей Lua с парами ключ-значение аргументов запроса, например

ngx.req.set_uri_args({ a = 3, b = "hello world" })

В первом случае, когда вся строка запроса передаётся напрямую, входная строка Lua уже должна быть корректно закодирована для URI. Из соображений безопасности этот метод автоматически экранирует в строке Lua все управляющие символы и пробельные символы (коды ASCII от 0x00 до 0x20 и 0x7F).

Во втором случае метод экранирует ключи и значения аргументов согласно правилам экранирования URI.

Поддерживаются также аргументы с несколькими значениями:

ngx.req.set_uri_args({ a = 3, b = {5, 6} })

В результате получится строка запроса вида a=3&b=5&b=6 или b=5&b=6&a=3.

Обратите внимание: если в качестве аргумента arg используется таблица Lua, порядок аргументов в результирующей строке запроса может меняться. Чтобы получить результат с фиксированным порядком, используйте строку Lua в качестве аргумента arg.

Этот интерфейс впервые появился в выпуске v0.3.1rc13.

См. также ngx.req.set_uri.

ngx.req.get_uri_args

синтаксис: args, err = ngx.req.get_uri_args(max_args?, tab?)

контекст: set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, balancer_by_lua*

Возвращает таблицу Lua со всеми аргументами URL-запроса текущего запроса. Необязательный аргумент tab можно использовать для повторного использования таблицы, возвращённой этим методом.

location = /test {
    content_by_lua_block {
        local args, err = ngx.req.get_uri_args()

        if err == "truncated" then
            -- one can choose to ignore or reject the current request here
        end

        for key, val in pairs(args) do
            if type(val) == "table" then
                ngx.say(key, ": ", table.concat(val, ", "))
            else
                ngx.say(key, ": ", val)
            end
        end
    }
}

Тогда GET /test?foo=bar&bar=baz&bar=blah вернёт тело ответа

foo: bar
bar: baz, blah

Если ключ аргумента встречается несколько раз, значением будет таблица, содержащая все значения этого ключа в исходном порядке.

Ключи и значения декодируются согласно правилам декодирования URI. При указанных выше настройках GET /test?a%20b=1%61+2 вернёт:

a b: 1a 2

Аргументы без частей =<value> считаются логическими аргументами. GET /test?foo&bar вернёт:

foo: true
bar: true

То есть им будут присвоены логические значения Lua true. Однако они отличаются от аргументов со значениями в виде пустой строки. GET /test?foo=&bar= вернёт примерно следующее:

foo:
bar:

Аргументы с пустыми ключами отбрасываются. Например, GET /test?=hello&=world вернёт пустой результат.

Также поддерживается изменение аргументов запроса во время выполнения с помощью переменной Nginx $args (или ngx.var.args в Lua):

ngx.var.args = "a=3&b=42"
local args, err = ngx.req.get_uri_args()

В этом случае таблица args всегда будет иметь вид

{a = 3, b = 42}

независимо от фактической строки запроса.

Обратите внимание: по умолчанию разбирается не более 100 аргументов запроса (включая аргументы с одинаковыми именами); остальные аргументы молча отбрасываются для защиты от потенциальных атак типа «отказ в обслуживании». Начиная с v0.10.13, при превышении лимита возвращается второе значение — строка "truncated".

Однако этот лимит можно изменить с помощью необязательного аргумента функции max_args:

local args, err = ngx.req.get_uri_args(10)
if err == "truncated" then
    -- one can choose to ignore or reject the current request here
end

Чтобы снять лимит и обработать все полученные аргументы запроса, этому аргументу можно присвоить ноль:

local args, err = ngx.req.get_uri_args(0)

Настоятельно не рекомендуется снимать ограничение max_args.

ngx.req.get_post_args

синтаксис: args, err = ngx.req.get_post_args(max_args?)

контекст: rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*

Возвращает таблицу Lua со всеми аргументами POST-запроса текущего запроса (типа MIME application/x-www-form-urlencoded). Сначала вызовите ngx.req.read_body, чтобы прочитать тело запроса, или включите директиву lua_need_request_body, чтобы избежать ошибок.

location = /test {
    content_by_lua_block {
        ngx.req.read_body()
        local args, err = ngx.req.get_post_args()

        if err == "truncated" then
            -- one can choose to ignore or reject the current request here
        end

        if not args then
            ngx.say("failed to get post args: ", err)
            return
        end
        for key, val in pairs(args) do
            if type(val) == "table" then
                ngx.say(key, ": ", table.concat(val, ", "))
            else
                ngx.say(key, ": ", val)
            end
        end
    }
}

Затем

# Post request with the body 'foo=bar&bar=baz&bar=blah'
$ curl --data 'foo=bar&bar=baz&bar=blah' localhost/test

вернёт тело ответа, например:

foo: bar
bar: baz, blah

Если ключ аргумента встречается несколько раз, значением будет таблица, содержащая все значения этого ключа в исходном порядке.

Ключи и значения декодируются согласно правилам декодирования URI.

При указанных выше настройках

# POST request with body 'a%20b=1%61+2'
$ curl -d 'a%20b=1%61+2' localhost/test

вернёт:

a b: 1a 2

Аргументы без частей =<value> считаются логическими аргументами. POST /test с телом запроса foo&bar вернёт:

foo: true
bar: true

То есть им будут присвоены логические значения Lua true. Однако они отличаются от аргументов со значениями в виде пустой строки. POST /test с телом запроса foo=&bar= вернёт примерно следующее:

foo:
bar:

Аргументы с пустыми ключами отбрасываются. Например, POST /test с телом =hello&=world вернёт пустой результат.

Обратите внимание: по умолчанию разбирается не более 100 аргументов запроса (включая аргументы с одинаковыми именами); остальные аргументы молча отбрасываются для защиты от потенциальных атак типа «отказ в обслуживании». Начиная с v0.10.13, при превышении лимита возвращается второе значение — строка "truncated".

Однако этот лимит можно изменить с помощью необязательного аргумента функции max_args:

local args, err = ngx.req.get_post_args(10)
if err == "truncated" then
    -- one can choose to ignore or reject the current request here
end

Чтобы снять лимит и обработать все полученные аргументы запроса, этому аргументу можно присвоить ноль:

local args, err = ngx.req.get_post_args(0)

Настоятельно не рекомендуется снимать ограничение max_args.

ngx.req.get_headers

синтаксис: headers, err = ngx.req.get_headers(max_headers?, raw?)

контекст: set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*

Возвращает таблицу Lua со всеми заголовками текущего запроса.

local h, err = ngx.req.get_headers()

if err == "truncated" then
    -- one can choose to ignore or reject the current request here
end

for k, v in pairs(h) do
    ...
end

Чтобы прочитать отдельный заголовок:

ngx.say("Host: ", ngx.req.get_headers()["Host"])

Обратите внимание: для чтения отдельных заголовков запроса может быть предпочтительнее API ngx.var.HEADER, использующий встроенные переменные $http_HEADER.

Если заголовок запроса встречается несколько раз, например:

Foo: foo
Foo: bar
Foo: baz

значением ngx.req.get_headers()["Foo"] будет таблица Lua (массив), например:

{"foo", "bar", "baz"}

Обратите внимание: по умолчанию разбирается не более 100 заголовков запроса (включая заголовки с одинаковыми именами); остальные заголовки молча отбрасываются для защиты от потенциальных атак типа «отказ в обслуживании». Начиная с v0.10.13, при превышении лимита возвращается второе значение — строка "truncated".

Однако этот лимит можно изменить с помощью необязательного аргумента функции max_headers:

local headers, err = ngx.req.get_headers(10)

if err == "truncated" then
    -- one can choose to ignore or reject the current request here
end

Чтобы снять лимит и обработать все полученные заголовки запроса, этому аргументу можно присвоить ноль:

local headers, err = ngx.req.get_headers(0)

Настоятельно не рекомендуется снимать ограничение max_headers.

Начиная с выпуска 0.6.9, все имена заголовков в возвращаемой таблице Lua по умолчанию переводятся в нижний регистр, если аргумент raw не установлен в true (по умолчанию false).

Кроме того, по умолчанию к результирующей таблице Lua добавляется метаметод __index, который при промахе при поиске нормализует ключи, переводя их в нижний регистр и заменяя все символы подчёркивания дефисами. Например, если присутствует заголовок запроса My-Foo-Header, следующие обращения корректно получат значение этого заголовка:

ngx.say(headers.my_foo_header)
ngx.say(headers["My-Foo-Header"])
ngx.say(headers["my-foo-header"])

Метаметод __index не будет добавлен, если аргумент raw установлен в true.

ngx.req.set_header

синтаксис: ngx.req.set_header(header_name, header_value)

контекст: set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*

Устанавливает значение header_value для заголовка запроса текущего запроса с именем header_name, переопределяя все существующие значения.

Входные строки Lua header_name и header_value уже должны быть корректно закодированы для URI. Из соображений безопасности этот метод автоматически экранирует в header_name символы " ", """, "(", ")", ",", "/", ":", ";", "?", "<", "=", ">", "?", "@", "[", "]", "", "{", "}", 0x00-0x1F, 0x7F-0xFF, а в header_value — символы "0x00-0x08, 0x0A-0x0F, 0x7F.

По умолчанию все подзапросы, впоследствии инициированные с помощью ngx.location.capture и ngx.location.capture_multi, будут наследовать новый заголовок.

Это не является эквивалентом директивы nginx proxy_set_header на Lua (то же относится к ngx.req.clear_header). proxy_set_header влияет только на запрос к upstream, тогда как ngx.req.set_header изменяет входящий запрос. Различие будет видно в записи HTTP-заголовков в журнале доступа. Тем не менее эту функцию можно использовать как альтернативу директиве nginx proxy_set_header, если учитывать это различие.

Пример установки заголовка Content-Type:

ngx.req.set_header("Content-Type", "text/css")

В качестве значения header_value можно передать список значений, например:

ngx.req.set_header("Foo", {"a", "abc"})

Это создаст два новых заголовка запроса:

Foo: a
Foo: abc

При этом старые заголовки Foo будут переопределены, если они существуют.

Если аргумент header_value равен nil, заголовок запроса будет удалён. Поэтому

ngx.req.set_header("X-Foo", nil)

эквивалентно следующему:

ngx.req.clear_header("X-Foo")

Примечание: эта функция вызывает ошибку Lua, если header_name или header_value содержит небезопасные символы (управляющие символы).

ngx.req.clear_header

синтаксис: ngx.req.clear_header(header_name)

контекст: set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*

Удаляет заголовок запроса текущего запроса с именем header_name. Это не повлияет на существующие подзапросы текущего запроса, но впоследствии инициированные подзапросы по умолчанию унаследуют это изменение.

ngx.req.read_body

синтаксис: ngx.req.read_body()

контекст: rewrite_by_lua*, access_by_lua*, content_by_lua*

Синхронно читает тело запроса клиента, не блокируя цикл обработки событий Nginx.

ngx.req.read_body()
local args = ngx.req.get_post_args()

Если тело запроса уже было прочитано благодаря включённой директиве lua_need_request_body или другими модулями, эта функция не выполняет никаких действий и сразу возвращает управление.

Если тело запроса уже было явно отброшено функцией ngx.req.discard_body или другими модулями, эта функция не выполняет никаких действий и сразу возвращает управление.

В случае ошибок, например при сбое соединения во время чтения данных, этот метод вызовет исключение Lua или немедленно завершит текущий запрос с кодом состояния 500.

Данные тела запроса, прочитанные этой функцией, впоследствии можно получить с помощью ngx.req.get_body_data либо получить имя временного файла с данными тела, сохранёнными на диске, с помощью ngx.req.get_body_file. Это зависит от следующих условий:

  1. превышает ли размер тела текущего запроса значение client_body_buffer_size,
  2. и включена ли директива client_body_in_file_only.

Если у текущего запроса может быть тело, но данные тела не нужны, необходимо использовать функцию ngx.req.discard_body, чтобы явно отбросить тело запроса и избежать проблем при использовании HTTP 1.1 keepalive или конвейерной передачи HTTP 1.1.

Эта функция впервые появилась в выпуске v0.3.1rc17.

ngx.req.discard_body

синтаксис: ngx.req.discard_body()

контекст: rewrite_by_lua*, access_by_lua*, content_by_lua*

Явно отбрасывает тело запроса: читает данные из соединения и немедленно отбрасывает их (не используя тело запроса ни для каких целей).

Эта функция выполняется асинхронно и возвращает управление немедленно.

Если тело запроса уже было прочитано, функция ничего не делает и сразу возвращает управление.

Эта функция впервые появилась в выпуске v0.3.1rc17.

См. также ngx.req.read_body.

ngx.req.get_body_data

синтаксис: data = ngx.req.get_body_data(max_bytes?)

контекст: rewrite_by_lua*, access_by_lua*, content_by_lua*, log_by_lua*

Получает данные тела запроса, хранящиеся в памяти. Функция возвращает строку Lua, а не таблицу Lua со всеми разобранными аргументами запроса. Если нужна таблица Lua, используйте функцию ngx.req.get_post_args.

Необязательный аргумент max_bytes можно использовать, если требуется не всё тело целиком.

Функция возвращает nil в следующих случаях:

  1. тело запроса не было прочитано;
  2. тело запроса было прочитано во временные файлы на диске;
  3. или размер тела запроса равен нулю.

Если тело запроса ещё не прочитано, сначала вызовите ngx.req.read_body (или включите lua_need_request_body, чтобы принудительно прочитать тело запроса с помощью этого модуля; однако это не рекомендуется).

Если тело запроса было прочитано в файлы на диске, попробуйте вместо этого вызвать функцию ngx.req.get_body_file.

Чтобы хранить тела запросов в памяти, попробуйте установить для client_body_buffer_size значение, равное client_max_body_size.

Обратите внимание: вызов этой функции вместо использования ngx.var.request_body или ngx.var.echo_request_body эффективнее, поскольку позволяет избежать одного выделения динамической памяти и одного копирования данных.

Эта функция впервые появилась в выпуске v0.3.1rc17.

См. также ngx.req.get_body_file.

ngx.req.get_body_file

синтаксис: file_name = ngx.req.get_body_file()

контекст: rewrite_by_lua*, access_by_lua*, content_by_lua*

Получает имя файла с данными тела запроса, хранящимися в файле. Возвращает nil, если тело запроса не было прочитано или было прочитано в память.

Возвращённый файл доступен только для чтения и обычно удаляется пулом памяти Nginx. Его нельзя вручную изменять, переименовывать или удалять в коде Lua.

Если тело запроса ещё не прочитано, сначала вызовите ngx.req.read_body (или включите lua_need_request_body, чтобы принудительно прочитать тело запроса с помощью этого модуля; однако это не рекомендуется).

Если тело запроса было прочитано в память, попробуйте вместо этого вызвать функцию ngx.req.get_body_data.

Чтобы принудительно сохранять тела запросов в файлах, попробуйте включить client_body_in_file_only.

Обратите внимание: эта функция работает и на фазе балансировщика, но после установки данных тела запроса или заголовков необходимо вызвать balancer.recreate_request, чтобы изменения вступили в силу.

Эта функция впервые появилась в выпуске v0.3.1rc17.

См. также ngx.req.get_body_data.

ngx.req.set_body_data

синтаксис: ngx.req.set_body_data(data)

контекст: rewrite_by_lua*, access_by_lua*, content_by_lua*, balancer_by_lua*,

Устанавливает тело текущего запроса, используя данные в памяти, указанные аргументом data.

Если тело запроса ещё не прочитано, сначала вызовите ngx.req.read_body (или включите lua_need_request_body, чтобы принудительно прочитать тело запроса с помощью этого модуля; однако это не рекомендуется). Кроме того, тело запроса не должно быть ранее отброшено с помощью ngx.req.discard_body.

Независимо от того, было ли предыдущее тело запроса прочитано в память или сохранено во временном файле на диске, оно будет освобождено, а файл немедленно удалён.

Обратите внимание: эта функция работает и на фазе балансировщика, но после установки данных тела запроса или заголовков необходимо вызвать balancer.recreate_request, чтобы изменения вступили в силу.

Эта функция впервые появилась в выпуске v0.3.1rc18.

См. также ngx.req.set_body_file.

ngx.req.set_body_file

синтаксис: ngx.req.set_body_file(file_name, auto_clean?)

контекст: rewrite_by_lua*, access_by_lua*, content_by_lua*, balancer_by_lua*,

Устанавливает тело текущего запроса, используя данные из файла, указанного аргументом file_name.

Если тело запроса ещё не прочитано, сначала вызовите ngx.req.read_body (или включите lua_need_request_body, чтобы принудительно прочитать тело запроса с помощью этого модуля; однако это не рекомендуется). Кроме того, тело запроса не должно быть ранее отброшено с помощью ngx.req.discard_body.

Если для необязательного аргумента auto_clean задано значение true, файл будет удалён по завершении обработки запроса или при следующем вызове этой функции либо ngx.req.set_body_data в том же запросе. По умолчанию auto_clean имеет значение false.

Убедитесь, что файл, указанный аргументом file_name, существует и доступен для чтения рабочему процессу Nginx; задайте соответствующие разрешения, чтобы избежать ошибок-исключений Lua.

Независимо от того, было ли предыдущее тело запроса прочитано в память или сохранено во временном файле на диске, оно будет освобождено, а файл немедленно удалён.

Эта функция впервые появилась в выпуске v0.3.1rc18.

См. также ngx.req.set_body_data.

ngx.req.init_body

синтаксис: ngx.req.init_body(buffer_size?)

контекст: set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*

Создаёт новое пустое тело для текущего запроса и инициализирует буфер для последующей записи данных тела запроса с помощью API ngx.req.append_body и ngx.req.finish_body.

Если указан аргумент buffer_size, его значение будет использовано как размер буфера памяти для записи тела с помощью ngx.req.append_body. Если аргумент не указан, вместо него будет использовано значение стандартной директивы client_body_buffer_size.

Когда данные перестанут помещаться в буфер памяти тела запроса, они будут сброшены во временный файл, как и при стандартном чтении тела запроса в ядре Nginx.

После добавления всех данных в тело текущего запроса важно всегда вызывать ngx.req.finish_body. Кроме того, если эта функция используется вместе с ngx.req.socket, необходимо вызвать ngx.req.socket до этой функции, иначе появится сообщение об ошибке «request body already exists».

Обычно эта функция используется следующим образом:

ngx.req.init_body(128 * 1024)  -- buffer is 128KB
for chunk in next_data_chunk() do
    ngx.req.append_body(chunk) -- each chunk can be 4KB
end
ngx.req.finish_body()

Эту функцию можно использовать вместе с ngx.req.append_body, ngx.req.finish_body и ngx.req.socket для реализации эффективных входных фильтров на чистом Lua (в контексте rewrite_by_lua* или access_by_lua*); такие фильтры можно использовать с другими обработчиками содержимого или upstream-модулями Nginx, например ngx_http_proxy_module и ngx_http_fastcgi_module.

Эта функция впервые появилась в выпуске v0.5.11.

ngx.req.append_body

синтаксис: ngx.req.append_body(data_chunk)

контекст: set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*

Добавляет новый фрагмент данных, указанный аргументом data_chunk, к существующему телу запроса, созданному вызовом ngx.req.init_body.

Когда данные перестанут помещаться в буфер памяти тела запроса, они будут сброшены во временный файл, как и при стандартном чтении тела запроса в ядре Nginx.

После добавления всех данных в тело текущего запроса важно всегда вызывать ngx.req.finish_body.

Эту функцию можно использовать вместе с ngx.req.init_body, ngx.req.finish_body и ngx.req.socket для реализации эффективных фильтров входящих данных на чистом Lua (в контексте rewrite_by_lua* или access_by_lua*), которые можно использовать с другими обработчиками содержимого Nginx или модулями upstream, например ngx_http_proxy_module и ngx_http_fastcgi_module.

Эта функция впервые появилась в выпуске v0.5.11.

См. также ngx.req.init_body.

ngx.req.finish_body

синтаксис: ngx.req.finish_body()

контекст: set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*

Завершает создание нового тела запроса, начатое вызовами ngx.req.init_body и ngx.req.append_body.

Эту функцию можно использовать вместе с ngx.req.init_body, ngx.req.append_body и ngx.req.socket для реализации эффективных фильтров входящих данных на чистом Lua (в контексте rewrite_by_lua* или access_by_lua*), которые можно использовать с другими обработчиками содержимого Nginx или модулями upstream, например ngx_http_proxy_module и ngx_http_fastcgi_module.

Эта функция впервые появилась в выпуске v0.5.11.

См. также ngx.req.init_body.

ngx.req.socket

синтаксис: tcpsock, err = ngx.req.socket()

синтаксис: tcpsock, err = ngx.req.socket(raw)

контекст: rewrite_by_lua*, access_by_lua*, content_by_lua*

Возвращает доступный только для чтения объект cosocket, оборачивающий downstream-соединение. Для этого объекта поддерживаются только методы receive, receiveany и receiveuntil.

В случае ошибки также возвращается nil и строка с описанием ошибки.

Примечание: Этот метод блокирует выполнение, пока тело запроса клиента не будет получено полностью. Время блокировки зависит от директивы client_body_timeout и максимального размера тела, заданного директивой client_max_body_size. Если истечет время ожидания чтения или размер тела клиента превысит установленный предел, эта функция не вернет управление, а клиенту будет отправлен ответ 408 Request Time-out или 413 Request Entity Too Large.

Объект сокета, возвращаемый этим методом, обычно используется для потокового чтения тела текущего запроса. Не включайте директиву lua_need_request_body и не сочетайте этот вызов с ngx.req.read_body и ngx.req.discard_body.

Если какие-либо данные тела запроса были предварительно прочитаны во внутренний буфер заголовка запроса Nginx, возвращаемый объект cosocket обработает их, чтобы избежать потенциальной потери данных из-за такого предварительного чтения. Тела запросов с фрагментированным кодированием в этом API пока не поддерживаются.

Начиная с выпуска v0.9.0 эта функция принимает необязательный аргумент типа boolean raw. Если этот аргумент имеет значение true, функция возвращает полнодуплексный объект cosocket, оборачивающий необработанный сокет downstream-соединения. Для него можно вызывать методы receive, receiveany, receiveuntil и send.

Если аргумент raw имеет значение true, необходимо, чтобы не оставалось ожидающих данных от предыдущих вызовов ngx.say, ngx.print или ngx.send_headers. Поэтому, если ранее выполнялись эти вызовы для вывода данных клиенту, перед вызовом ngx.req.socket(true) следует вызвать ngx.flush(true), чтобы убедиться в отсутствии ожидающих данных вывода. Если тело запроса еще не было прочитано, этот «необработанный сокет» также можно использовать для чтения тела запроса.

Возвращаемый ngx.req.socket(true) «необработанный сокет запроса» можно использовать для реализации сложных протоколов, например WebSocket, или для отправки собственных необработанных заголовков и данных тела HTTP-ответа. Реальный пример можно найти в библиотеке lua-resty-websocket.

Эта функция впервые появилась в выпуске v0.5.0rc1.

ngx.exec

синтаксис: ngx.exec(uri, args?)

контекст: rewrite_by_lua*, access_by_lua*, content_by_lua*

Выполняет внутреннее перенаправление на uri с args; функция аналогична директиве echo_exec модуля echo-nginx-module.

ngx.exec('/some-location')
ngx.exec('/some-location', 'a=3&b=5&c=6')
ngx.exec('/some-location?a=3&b=5', 'c=6')

Необязательный второй аргумент args можно использовать для указания дополнительных аргументов URI-запроса, например:

ngx.exec("/foo", "a=3&b=hello%20world")

Вместо этого для аргумента args можно передать таблицу Lua, чтобы ngx_lua выполнил экранирование URI и конкатенацию строк.

ngx.exec("/foo", { a = 3, b = "hello world" })

Результат будет точно таким же, как в предыдущем примере.

Формат таблицы Lua, передаваемой как аргумент args, совпадает с форматом, используемым методом ngx.encode_args.

Поддерживаются и именованные локации, но второй аргумент args будет проигнорирован, если он указан, а строка запроса для нового целевого адреса будет унаследована от исходной локации (если она есть).

В примере ниже GET /foo/file.php?a=hello вернет «hello», а не «goodbye»

location /foo {
    content_by_lua_block {
        ngx.exec("@bar", "a=goodbye")
    }
}

location @bar {
    content_by_lua_block {
        local args = ngx.req.get_uri_args()
        for key, val in pairs(args) do
            if key == "a" then
                ngx.say(val)
            end
        end
    }
}

Обратите внимание, что метод ngx.exec отличается от ngx.redirect: он выполняет исключительно внутреннее перенаправление, не создавая нового внешнего HTTP-трафика.

Также учтите, что этот вызов завершает обработку текущего запроса и должен выполняться до ngx.send_headers или явного вывода тела ответа с помощью ngx.print либо ngx.say.

При использовании этого вызова вне контекста header_filter_by_lua* рекомендуется придерживаться стиля кодирования, при котором вызов совмещается с оператором return, то есть используется конструкция return ngx.exec(...), чтобы подчеркнуть, что обработка запроса завершается.

ngx.redirect

синтаксис: ngx.redirect(uri, status?)

контекст: rewrite_by_lua*, access_by_lua*, content_by_lua*

Выполняет перенаправление HTTP 301 или 302 на uri.

Примечание: эта функция вызывает ошибку Lua, если аргумент uri содержит небезопасные символы (управляющие символы).

Необязательный параметр status задает используемый код состояния HTTP. На данный момент поддерживаются следующие коды состояния:

  • 301
  • 302 (по умолчанию)
  • 303
  • 307
  • 308

По умолчанию используется 302 (ngx.HTTP_MOVED_TEMPORARILY).

Вот пример, в котором предполагается, что текущее имя сервера — localhost, а сервер прослушивает порт 1984:

return ngx.redirect("/foo")

что эквивалентно

return ngx.redirect("/foo", ngx.HTTP_MOVED_TEMPORARILY)

Поддерживается также перенаправление на произвольные внешние URL-адреса, например:

return ngx.redirect("http://www.google.com")

В качестве второго аргумента status можно также напрямую использовать числовой код:

return ngx.redirect("/foo", 301)

Этот метод аналогичен директиве rewrite с модификатором redirect в стандартном модуле ngx_http_rewrite_module; например, этот фрагмент nginx.conf

rewrite ^ /foo? redirect;  # nginx config

эквивалентен следующему коду Lua

return ngx.redirect('/foo')  -- Lua code

а

rewrite ^ /foo? permanent;  # nginx config

эквивалентен

return ngx.redirect('/foo', ngx.HTTP_MOVED_PERMANENTLY)  -- Lua code

Можно также указать аргументы URI, например:

return ngx.redirect('/foo?a=3&b=4')

Обратите внимание, что этот вызов завершает обработку текущего запроса и должен выполняться до ngx.send_headers или явного вывода тела ответа с помощью ngx.print либо ngx.say.

При использовании этого вызова вне контекста header_filter_by_lua* рекомендуется придерживаться стиля кодирования, при котором вызов совмещается с оператором return, то есть используется конструкция return ngx.redirect(...), чтобы подчеркнуть, что обработка запроса завершается.

ngx.send_headers

синтаксис: ok, err = ngx.send_headers()

контекст: rewrite_by_lua*, access_by_lua*, content_by_lua*

Явно отправляет заголовки ответа.

Начиная с v0.8.3 эта функция при успешном выполнении возвращает 1, а в противном случае возвращает nil и строку с описанием ошибки.

Обычно нет необходимости вручную отправлять заголовки ответа: ngx_lua автоматически отправит их перед выводом содержимого с помощью ngx.say или ngx.print либо при обычном завершении работы content_by_lua*.

ngx.headers_sent

синтаксис: value = ngx.headers_sent

контекст: set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*

Возвращает true, если заголовки ответа были отправлены (модулем ngx_lua), и false в противном случае.

Этот API впервые появился в ngx_lua v0.3.1rc6.

ngx.print

синтаксис: ok, err = ngx.print(...)

контекст: rewrite_by_lua*, access_by_lua*, content_by_lua*

Отправляет HTTP-клиенту аргументы, объединенные в одну строку (как тело ответа). Если заголовки ответа еще не отправлены, эта функция сначала отправит заголовки, а затем выведет данные тела.

Начиная с v0.8.3 эта функция при успешном выполнении возвращает 1, а в противном случае возвращает nil и строку с описанием ошибки.

Значения Lua типа nil выводятся как строки "nil", а логические значения Lua выводятся как строковые литералы "true" и "false" соответственно.

Допускаются вложенные массивы строк; их элементы отправляются по одному:

local table = {
    "hello, ",
    {"world: ", true, " or ", false,
        {": ", nil}}
}
ngx.print(table)

будет выведено следующее:

hello, world: true or false: nil

Аргументы-таблицы, не являющиеся массивами, вызовут исключение Lua.

Константа ngx.null приведет к выводу строки "null".

Это асинхронный вызов, который немедленно возвращает управление, не дожидаясь записи всех данных в системный буфер отправки. Чтобы использовать синхронный режим, вызовите ngx.flush(true) после вызова ngx.print. Это может быть особенно полезно при потоковом выводе. Подробнее см. в разделе ngx.flush.

Обратите внимание, что и ngx.print, и ngx.say всегда запускают всю цепочку фильтров тела вывода Nginx, что является затратной операцией. Поэтому будьте осторожны при вызове любой из этих функций в тесном цикле: накапливайте данные в Lua самостоятельно и сократите число вызовов.

ngx.say

синтаксис: ok, err = ngx.say(...)

контекст: rewrite_by_lua*, access_by_lua*, content_by_lua*

Работает так же, как ngx.print, но дополнительно выводит завершающий символ новой строки.

ngx.log

синтаксис: ngx.log(log_level, ...)

контекст: init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, exit_worker_by_lua*, ssl_client_hello_by_lua*

Записывает в error.log аргументы, объединенные в одну строку, с указанным уровнем ведения журнала.

Допускаются аргументы Lua типа nil; они преобразуются в строку-литерал "nil". Логические значения Lua преобразуются в строковые литералы "true" или "false". Константа ngx.null приводит к выводу строки "null".

Аргумент log_level может принимать такие константы, как ngx.ERR и ngx.WARN. Подробнее см. в разделе Константы уровней ведения журнала Nginx.

В ядре Nginx жестко задано ограничение 2048 байт на длину сообщений об ошибках. Это ограничение включает завершающие символы новой строки и начальные временные метки. Если размер сообщения превышает этот предел, Nginx соответственно обрежет текст сообщения. Это ограничение можно изменить вручную, отредактировав определение макроса NGX_MAX_ERROR_STR в файле src/core/ngx_log.h в исходном дереве Nginx.

ngx.flush

синтаксис: ok, err = ngx.flush(wait?)

контекст: rewrite_by_lua*, access_by_lua*, content_by_lua*

Сбрасывает вывод ответа клиенту.

ngx.flush принимает необязательный аргумент типа boolean wait (по умолчанию: false), впервые добавленный в выпуске v0.3.1rc34. При вызове со значением аргумента по умолчанию функция выполняет асинхронный вызов (немедленно возвращает управление, не дожидаясь записи данных вывода в системный буфер отправки). Если установить аргумент wait в значение true, функция переключается в синхронный режим.

В синхронном режиме функция не вернет управление, пока все данные вывода не будут записаны в системный буфер отправки или пока не истечет интервал, заданный параметром send_timeout. Обратите внимание, что благодаря механизму сопрограмм Lua эта функция не блокирует цикл событий Nginx даже в синхронном режиме.

Вызов ngx.flush(true) сразу после ngx.print или ngx.say приводит к тому, что эти функции выполняются в синхронном режиме. Это может быть особенно полезно при потоковом выводе.

Обратите внимание, что ngx.flush не работает в режиме буферизации вывода HTTP 1.0. См. раздел Поддержка HTTP 1.0.

Начиная с v0.8.3 эта функция при успешном выполнении возвращает 1, а в противном случае возвращает nil и строку с описанием ошибки.

ngx.exit

синтаксис: ngx.exit(status)

контекст: rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, ssl_client_hello_by_lua*

Если status >= 200 (то есть ngx.HTTP_OK или выше), функция прервет выполнение текущего запроса и вернет код состояния в Nginx.

Если status == 0 (то есть ngx.OK), функция только завершит текущий обработчик фазы (или обработчик содержимого, если используется директива content_by_lua*) и продолжит выполнение последующих фаз (если они есть) для текущего запроса.

Аргумент status может принимать значения ngx.OK, ngx.ERROR, ngx.HTTP_NOT_FOUND, ngx.HTTP_MOVED_TEMPORARILY или другие константы состояния HTTP.

Чтобы вернуть страницу ошибки с пользовательским содержимым, используйте фрагменты кода, подобные следующему:

ngx.status = ngx.HTTP_GONE
ngx.say("This is our own content")
-- to cause quit the whole request rather than the current phase handler
ngx.exit(ngx.HTTP_OK)

Результат работы:

$ curl -i http://localhost/test
HTTP/1.1 410 Gone
Server: nginx/1.0.6
Date: Thu, 15 Sep 2011 00:51:48 GMT
Content-Type: text/plain
Transfer-Encoding: chunked
Connection: keep-alive

This is our own content

В качестве аргумента можно непосредственно использовать числовые литералы, например:

ngx.exit(501)

Обратите внимание: хотя этот метод принимает в качестве входных данных все константы состояния HTTP, из констант ядра он принимает только ngx.OK и ngx.ERROR.

Также учтите, что этот вызов завершает обработку текущего запроса. Чтобы подчеркнуть, что обработка запроса завершается, рекомендуется использовать стиль кодирования, при котором вызов совмещается с оператором return, то есть конструкцию return ngx.exit(...).

При использовании в контекстах header_filter_by_lua*, balancer_by_lua* и ssl_session_store_by_lua* вызов ngx.exit() выполняется асинхронно и немедленно возвращает управление. Такое поведение может измениться в будущем; пользователям рекомендуется всегда использовать return в сочетании с ним, как указано выше.

ngx.eof

синтаксис: ok, err = ngx.eof()

контекст: rewrite_by_lua*, access_by_lua*, content_by_lua*

Явно указывает конец потока вывода ответа. В случае вывода с фрагментированным кодированием HTTP 1.1 это просто заставляет ядро Nginx отправить «последний фрагмент».

Если для downstream-соединений отключена функция keep-alive HTTP 1.1, можно рассчитывать, что правильно реализованные HTTP-клиенты самостоятельно закроют соединение после вызова этого метода. Этот прием можно использовать для выполнения фоновых задач, не заставляя HTTP-клиентов ждать завершения соединения, как в следующем примере:

location = /async {
    keepalive_timeout 0;
    content_by_lua_block {
        ngx.say("got the task!")
        ngx.eof()  -- well written HTTP clients will close the connection at this point
        -- access MySQL, PostgreSQL, Redis, Memcached, and etc here...
    }
}

Но если вы создаете подзапросы для обращения к другим локациям, настроенным модулями upstream Nginx, необходимо настроить эти модули так, чтобы они игнорировали разрывы соединения клиентом, если такое поведение не задано по умолчанию. Например, стандартный модуль ngx_http_proxy_module по умолчанию завершает и подзапрос, и основной запрос сразу после закрытия соединения клиентом. Поэтому важно включить директиву proxy_ignore_client_abort в блоке location, настроенном с помощью ngx_http_proxy_module:

proxy_ignore_client_abort on;

Для фоновых задач лучше использовать API ngx.timer.at.

Начиная с v0.8.3 эта функция при успешном выполнении возвращает 1, а в противном случае возвращает nil и строку с описанием ошибки.

ngx.sleep

синтаксис: ngx.sleep(seconds)

контекст: rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_client_hello_by_lua*

Приостанавливает выполнение на указанное число секунд, не блокируя его. Можно задать точность времени до 0,001 секунды (то есть до одной миллисекунды).

Внутри этот метод использует таймеры Nginx.

Начиная с выпуска 0.7.20, аргумент времени 0 также можно указывать.

Этот метод появился в выпуске 0.5.0rc30.

ngx.escape_uri

синтаксис: newstr = ngx.escape_uri(str, type?)

контекст: init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, exit_worker_by_lua*, ssl_client_hello_by_lua*

Начиная с v0.10.16 эта функция принимает необязательный аргумент type. Допустимы следующие значения (по умолчанию используется 2):

  • 0: экранирует str как полный URI. Экранируются также символы «пробел», #, %, ?, 0x00 ~ 0x1F и 0x7F ~ 0xFF.
  • 2: экранирует str как компонент URI. Все символы, кроме букв, цифр, -, ., _ и ~, кодируются как %XX.

ngx.unescape_uri

синтаксис: newstr = ngx.unescape_uri(str)

контекст: init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, exit_worker_by_lua*, ssl_client_hello_by_lua*

Снимает экранирование с str как с экранированного компонента URI.

Например,

ngx.say(ngx.unescape_uri("b%20r56+7"))

дает следующий результат:

b r56 7

Ошибочные последовательности экранирования обрабатываются обычным образом: % остаются без изменений. Символы, которые не должны встречаться в экранированной строке, также остаются без изменений.

Например,

ngx.say(ngx.unescape_uri("try %search%%20%again%"))

дает следующий результат:

try %search% %again%

(Обратите внимание: %20 после % был декодирован, хотя его можно считать частью ошибочной последовательности.)

ngx.encode_args

синтаксис: str = ngx.encode_args(table)

контекст: set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_client_hello_by_lua*

Преобразует таблицу Lua в строку аргументов запроса согласно правилам кодирования URI.

Например,

ngx.encode_args({foo = 3, ["b r"] = "hello world"})

дает

foo=3&b%20r=hello%20world

Ключи таблицы должны быть строками Lua.

Поддерживаются также аргументы запроса с несколькими значениями. Просто используйте таблицу Lua в качестве значения аргумента, например:

ngx.encode_args({baz = {32, "hello"}})

дает

baz=32&baz=hello

Если таблица значений пуста, результат эквивалентен значению nil.

Поддерживаются также логические значения аргументов, например:

ngx.encode_args({a = true, b = 1})

дает

a&b=1

Если значение аргумента равно false, результат эквивалентен значению nil.

Этот метод впервые появился в выпуске v0.3.1rc27.

ngx.decode_args

синтаксис: table, err = ngx.decode_args(str, max_args?)

контекст: set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, ssl_client_hello_by_lua*

Декодирует строку запроса с URI-кодированием в таблицу Lua. Эта функция обратна ngx.encode_args.

Необязательный аргумент max_args позволяет задать максимальное число аргументов, разбираемых из аргумента str. По умолчанию разбирается не более 100 аргументов запроса (включая аргументы с одинаковыми именами); остальные аргументы URI незаметно отбрасываются для защиты от потенциальных атак типа «отказ в обслуживании». Начиная с v0.10.13, при превышении этого ограничения возвращается второе значение — строка "truncated".

Чтобы снять ограничение и обрабатывать все полученные аргументы запроса, можно задать для этого аргумента нулевое значение:

local args = ngx.decode_args(str, 0)

Настоятельно не рекомендуется снимать ограничение max_args.

Этот метод появился в v0.5.0rc29.

ngx.encode_base64

синтаксис: newstr = ngx.encode_base64(str, no_padding?)

контекст: set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, ssl_client_hello_by_lua*

Кодирует str в дайджест base64. Для кодирования base64url используйте base64.encode_base64url.

Начиная с выпуска 0.9.16 можно указать необязательный аргумент no_padding логического типа, чтобы задать, следует ли добавлять заполнение base64 к полученному дайджесту (по умолчанию используется false, то есть заполнение включено).

ngx.decode_base64

синтаксис: newstr = ngx.decode_base64(str)

контекст: set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, ssl_client_hello_by_lua*

Декодирует аргумент str из base64-представления дайджеста в исходную форму. Для декодирования base64url используйте base64.decode_base64url.

Аргумент str должен быть закодирован в стандартном формате 'base64' согласно RFC 3548 или RFC 4648. Если формат некорректен или встречаются символы, отсутствующие в алфавите базового кодирования, будет возвращено nil. Заполняющие символы в конце входных данных можно опустить.

ngx.decode_base64mime

синтаксис: newstr = ngx.decode_base64mime(str)

контекст: set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*

требуется: resty.core.base64 или resty.core

Декодирует аргумент str из base64-представления дайджеста в исходную форму. Аргумент str соответствует формату передачи base64 для MIME (RFC 2045); символы, не входящие в алфавит базового кодирования, отбрасываются. Если str имеет некорректный формат, возвращается nil.

'''Примечание:''' для работы этого метода необходим модуль resty.core.base64 или resty.core из библиотеки lua-resty-core.

ngx.crc32_short

синтаксис: intval = ngx.crc32_short(str)

контекст: set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, ssl_client_hello_by_lua*

Вычисляет дайджест CRC-32 (циклический избыточный код) для аргумента str.

По сравнению с ngx.crc32_long этот метод эффективнее работает с относительно короткими входными данными str (то есть длиной менее 30 ~ 60 байт). Результат в точности совпадает с результатом ngx.crc32_long.

Внутри это всего лишь тонкая обёртка над функцией ngx_crc32_short, определённой в ядре Nginx.

Этот API впервые появился в выпуске v0.3.1rc8.

ngx.crc32_long

синтаксис: intval = ngx.crc32_long(str)

контекст: set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, ssl_client_hello_by_lua*

Вычисляет дайджест CRC-32 (циклический избыточный код) для аргумента str.

По сравнению с ngx.crc32_short этот метод эффективнее работает с относительно длинными входными данными str (то есть длиной более 30 ~ 60 байт). Результат в точности совпадает с результатом ngx.crc32_short.

Внутри это всего лишь тонкая обёртка над функцией ngx_crc32_long, определённой в ядре Nginx.

Этот API впервые появился в выпуске v0.3.1rc8.

ngx.hmac_sha1

синтаксис: digest = ngx.hmac_sha1(secret_key, str)

контекст: set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, ssl_client_hello_by_lua*

Вычисляет дайджест HMAC-SHA1 для аргумента str и преобразует результат с использованием секретного ключа <secret_key>.

Будет сгенерирована двоичная форма дайджеста HMAC-SHA1. Например, чтобы при необходимости представить результат в текстовом виде, используйте ngx.encode_base64.

Например,

local key = "thisisverysecretstuff"
local src = "some string we want to sign"
local digest = ngx.hmac_sha1(key, src)
ngx.say(ngx.encode_base64(digest))

даёт результат

R/pvxzHC4NLtj7S+kXFg/NePTmk=

Для работы этого API требуется, чтобы в сборке Nginx была включена библиотека OpenSSL (обычно для этого скрипту ./configure передают параметр --with-http_ssl_module).

Эта функция впервые появилась в выпуске v0.3.1rc29.

ngx.md5

синтаксис: digest = ngx.md5(str)

контекст: set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, ssl_client_hello_by_lua*

Возвращает шестнадцатеричное представление дайджеста MD5 аргумента str.

Например,

location = /md5 {
    content_by_lua_block {
        ngx.say(ngx.md5("hello"))
    }
}

даёт результат

5d41402abc4b2a76b9719d911017c592

Если требуется двоичный дайджест MD5, см. ngx.md5_bin.

ngx.md5_bin

синтаксис: digest = ngx.md5_bin(str)

контекст: set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, ssl_client_hello_by_lua*

Возвращает двоичную форму дайджеста MD5 аргумента str.

Если требуется шестнадцатеричная форма дайджеста MD5, см. ngx.md5.

ngx.sha1_bin

синтаксис: digest = ngx.sha1_bin(str)

контекст: set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, ssl_client_hello_by_lua*

Возвращает двоичную форму дайджеста SHA-1 аргумента str.

Для работы этой функции в сборке Nginx должна быть включена поддержка SHA-1. (Обычно достаточно установить OpenSSL перед сборкой Nginx.)

Эта функция впервые появилась в v0.5.0rc6.

ngx.quote_sql_str

синтаксис: quoted_value = ngx.quote_sql_str(raw_value)

контекст: set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, ssl_client_hello_by_lua*

Возвращает строковый литерал SQL в кавычках согласно правилам экранирования MySQL.

ngx.today

синтаксис: str = ngx.today()

контекст: init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, exit_worker_by_lua*, ssl_client_hello_by_lua*

Возвращает текущую дату (в формате yyyy-mm-dd) из кэша времени Nginx (системный вызов не выполняется, в отличие от библиотеки дат Lua).

Возвращается местное время.

ngx.time

синтаксис: secs = ngx.time()

контекст: init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, exit_worker_by_lua*, ssl_client_hello_by_lua*

Возвращает число секунд, прошедших с начала эпохи на момент текущей временной метки из кэша времени Nginx (системный вызов не выполняется, в отличие от библиотеки дат Lua).

Обновить кэш времени Nginx принудительно можно, предварительно вызвав ngx.update_time.

ngx.now

синтаксис: secs = ngx.now()

контекст: init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, exit_worker_by_lua*, ssl_client_hello_by_lua*

Возвращает число с плавающей точкой, обозначающее время в секундах (включая миллисекунды в дробной части), прошедшее с начала эпохи на момент текущей временной метки из кэша времени Nginx (системный вызов не выполняется, в отличие от библиотеки дат Lua).

Принудительно обновить кэш времени Nginx можно, предварительно вызвав ngx.update_time.

Этот API впервые появился в v0.3.1rc32.

ngx.update_time

синтаксис: ngx.update_time()

контекст: init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, exit_worker_by_lua*, ssl_client_hello_by_lua*

Принудительно обновляет кэш текущего времени Nginx. Этот вызов выполняет системный вызов и поэтому связан с некоторыми накладными расходами; не злоупотребляйте им.

Этот API впервые появился в v0.3.1rc32.

ngx.localtime

синтаксис: str = ngx.localtime()

контекст: init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, exit_worker_by_lua*, ssl_client_hello_by_lua*

Возвращает текущую временную метку (в формате yyyy-mm-dd hh:mm:ss) из кэша времени Nginx (системный вызов не выполняется, в отличие от функции os.date в Lua).

Возвращается местное время.

ngx.utctime

синтаксис: str = ngx.utctime()

контекст: init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, exit_worker_by_lua*, ssl_client_hello_by_lua*

Возвращает текущую временную метку (в формате yyyy-mm-dd hh:mm:ss) из кэша времени Nginx (системный вызов не выполняется, в отличие от функции os.date в Lua).

Возвращается время UTC.

ngx.cookie_time

синтаксис: str = ngx.cookie_time(sec)

контекст: init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, exit_worker_by_lua*, ssl_client_hello_by_lua*

Возвращает строку в формате, пригодном для указания срока действия cookie. Параметр sec — это временная метка в секундах (например, значение, возвращаемое ngx.time).

ngx.say(ngx.cookie_time(1290079655))
    -- yields "Thu, 18-Nov-10 11:27:35 GMT"

ngx.http_time

синтаксис: str = ngx.http_time(sec)

контекст: init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, exit_worker_by_lua*, ssl_client_hello_by_lua*

Возвращает строку в формате, пригодном для указания времени в HTTP-заголовке (например, в заголовке Last-Modified). Параметр sec — это временная метка в секундах (например, значение, возвращаемое ngx.time).

ngx.say(ngx.http_time(1290079655))
    -- yields "Thu, 18 Nov 2010 11:27:35 GMT"

ngx.parse_http_time

синтаксис: sec = ngx.parse_http_time(str)

контекст: init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, exit_worker_by_lua*, ssl_client_hello_by_lua*

Преобразует строку времени HTTP (возвращаемую ngx.http_time) в секунды. Возвращает число секунд или nil, если входная строка имеет некорректный формат.

local time = ngx.parse_http_time("Thu, 18 Nov 2010 11:27:35 GMT")
if time == nil then
    ...
end

ngx.is_subrequest

синтаксис: value = ngx.is_subrequest

контекст: set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*

Возвращает true, если текущий запрос является подзапросом Nginx, и false в противном случае.

ngx.re.match

синтаксис: captures, err = ngx.re.match(subject, regex, options?, ctx?, res_table?)

контекст: init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, exit_worker_by_lua*, ssl_client_hello_by_lua*

Ищет соответствие строки subject регулярному выражению regex, совместимому с Perl, с необязательным параметром options.

Возвращается только первое найденное совпадение или nil, если совпадений нет. При ошибках, например при некорректном регулярном выражении или превышении ограничения стека PCRE, возвращаются nil и строка с описанием ошибки.

Если совпадение найдено, возвращается таблица Lua captures, в которой captures[0] содержит всю совпавшую подстроку, captures[1] — результат захвата первой подмаски в круглых скобках, captures[2] — второй и так далее.

local m, err = ngx.re.match("hello, 1234", "[0-9]+")
if m then
    -- m[0] == "1234"

else
    if err then
        ngx.log(ngx.ERR, "error: ", err)
        return
    end

    ngx.say("match not found")
end
local m, err = ngx.re.match("hello, 1234", "([0-9])[0-9]+")
-- m[0] == "1234"
-- m[1] == "1"

Именованные захваты также поддерживаются начиная с выпуска v0.7.14 и возвращаются в той же таблице Lua в виде пар ключ-значение, как и нумерованные захваты.

local m, err = ngx.re.match("hello, 1234", "([0-9])(?<remaining>[0-9]+)")
-- m[0] == "1234"
-- m[1] == "1"
-- m[2] == "234"
-- m["remaining"] == "234"

Для несовпавших подмасок в полях таблицы captures будут значения false.

local m, err = ngx.re.match("hello, world", "(world)|(hello)|(?<named>howdy)")
-- m[0] == "hello"
-- m[1] == false
-- m[2] == "hello"
-- m[3] == false
-- m["named"] == false

Укажите options, чтобы задать способ выполнения операции поиска совпадения. Поддерживаются следующие символы параметров:

a             anchored mode (only match from the beginning)

d             enable the DFA mode (or the longest token match semantics).
              this requires PCRE 6.0+ or else a Lua exception will be thrown.
              first introduced in ngx_lua v0.3.1rc30.

D             enable duplicate named pattern support. This allows named
              subpattern names to be repeated, returning the captures in
              an array-like Lua table. for example,
                local m = ngx.re.match("hello, world",
                                       "(?<named>\w+), (?<named>\w+)",
                                       "D")
                -- m["named"] == {"hello", "world"}
              this option was first introduced in the v0.7.14 release.
              this option requires at least PCRE 8.12.

i             case insensitive mode (similar to Perl's /i modifier)

j             enable PCRE JIT compilation, this requires PCRE 8.21+ which
              must be built with the --enable-jit option. for optimum performance,
              this option should always be used together with the 'o' option.
              first introduced in ngx_lua v0.3.1rc30.

J             enable the PCRE Javascript compatible mode. this option was
              first introduced in the v0.7.14 release. this option requires
              at least PCRE 8.12.

m             multi-line mode (similar to Perl's /m modifier)

o             compile-once mode (similar to Perl's /o modifier),
              to enable the worker-process-level compiled-regex cache

s             single-line mode (similar to Perl's /s modifier)

u             UTF-8 mode. this requires PCRE to be built with
              the --enable-utf8 option or else a Lua exception will be thrown.

U             similar to "u" but disables PCRE's UTF-8 validity check on
              the subject string. first introduced in ngx_lua v0.8.1.

x             extended mode (similar to Perl's /x modifier)

Эти параметры можно комбинировать:

local m, err = ngx.re.match("hello, world", "HEL LO", "ix")
-- m[0] == "hello"
local m, err = ngx.re.match("hello, 美好生活", "HELLO, (.{2})", "iu")
-- m[0] == "hello, 美好"
-- m[1] == "美好"

Параметр o полезен для настройки производительности, поскольку соответствующий шаблон регулярного выражения компилируется только один раз, кэшируется на уровне рабочего процесса и используется совместно всеми запросами в текущем рабочем процессе Nginx. Максимальный размер кэша регулярных выражений можно настроить с помощью директивы lua_regex_cache_max_entries.

Необязательный четвёртый аргумент ctx может быть таблицей Lua с необязательным полем pos. Если в аргументе-таблице ctx задано поле pos, поиск ngx.re.match начнётся с указанного смещения (отсчёт начинается с 1). Независимо от наличия поля pos в таблице ctx, при успешном поиске ngx.re.match всегда устанавливает это поле pos в позицию после подстроки, совпавшей со всем шаблоном. Если совпадение не найдено, таблица ctx остаётся неизменной.

local ctx = {}
local m, err = ngx.re.match("1234, hello", "[0-9]+", "", ctx)
     -- m[0] = "1234"
     -- ctx.pos == 5
local ctx = { pos = 2 }
local m, err = ngx.re.match("1234, hello", "[0-9]+", "", ctx)
     -- m[0] = "234"
     -- ctx.pos == 5

Аргумент-таблицу ctx вместе с модификатором регулярного выражения a можно использовать для создания лексера на основе ngx.re.match.

Обратите внимание: аргумент options обязателен, если указан аргумент ctx. Если для options не требуется задавать значимые параметры регулярного выражения, в качестве заполнителя необходимо использовать пустую строку Lua ("").

Для работы этого метода в Nginx должна быть включена библиотека PCRE (Известная проблема со специальными escape-последовательностями).

Чтобы проверить, включён ли PCRE JIT, активируйте журнал отладки Nginx, добавив параметр --with-debug в скрипт ./configure Nginx или OpenResty. Затем включите уровень журнала ошибок "debug" в директиве error_log. Если PCRE JIT включён, будет выведено следующее сообщение:

pcre JIT compiling result: 1

Начиная с выпуска 0.9.4 эта функция также принимает пятый аргумент res_table, позволяющий вызывающему коду передать таблицу Lua для хранения всех результатов захвата. Начиная с 0.9.6, вызывающий код должен самостоятельно убедиться, что эта таблица пуста. Это удобно для повторного использования таблиц Lua и сокращения затрат на сборку мусора и выделение памяти под таблицы.

Эта возможность появилась в выпуске v0.2.1rc11.

ngx.re.find

синтаксис: from, to, err = ngx.re.find(subject, regex, options?, ctx?, nth?)

контекст: init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, exit_worker_by_lua*, ssl_client_hello_by_lua*

Подобно ngx.re.match, но возвращает только начальный индекс (from) и конечный индекс (to) совпавшей подстроки. Индексы начинаются с 1, поэтому их можно напрямую передавать API-функции string.sub, чтобы получить совпавшую подстроку.

При ошибках (например, некорректном регулярном выражении или ошибках времени выполнения PCRE) эта API-функция возвращает два значения nil, за которыми следует строка с описанием ошибки.

Если совпадение не найдено, функция просто возвращает значение nil.

Пример:

local s = "hello, 1234"
local from, to, err = ngx.re.find(s, "([0-9]+)", "jo")
if from then
    ngx.say("from: ", from)
    ngx.say("to: ", to)
    ngx.say("matched: ", string.sub(s, from, to))
else
    if err then
        ngx.say("error: ", err)
        return
    end
    ngx.say("not matched!")
end

В результате выполнения примера выводится:

from: 8
to: 11
matched: 1234

Поскольку эта API-функция не создаёт новых строк или таблиц Lua, она работает намного быстрее, чем ngx.re.match. По возможности следует использовать именно её.

Начиная с выпуска 0.9.3 поддерживается необязательный пятый аргумент nth, задающий индексы какого захвата (подсовпадения) нужно вернуть. Если nth равно 0 (значение по умолчанию), возвращаются индексы всей совпавшей подстроки; если nth равно 1, возвращаются индексы первого захвата подсовпадения; если nth равно 2, возвращаются индексы второго захвата подсовпадения и так далее. Если указанное подсовпадение не найдено, возвращаются два значения nil. Пример:

local str = "hello, 1234"
local from, to = ngx.re.find(str, "([0-9])([0-9]+)", "jo", nil, 2)
if from then
    ngx.say("matched 2nd submatch: ", string.sub(str, from, to))  -- yields "234"
end

Эта API-функция впервые появилась в выпуске v0.9.2.

ngx.re.gmatch

синтаксис: iterator, err = ngx.re.gmatch(subject, regex, options?)

контекст: init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, exit_worker_by_lua*, ssl_client_hello_by_lua*

Подобно ngx.re.match, но вместо этого возвращает итератор Lua, позволяющий программно перебрать все совпадения в строке <subject> с помощью PCRE regex.

При ошибках, например при некорректно сформированном регулярном выражении, возвращаются nil и строка с описанием ошибки.

Небольшой пример, демонстрирующий основное применение:

local iterator, err = ngx.re.gmatch("hello, world!", "([a-z]+)", "i")
if not iterator then
    ngx.log(ngx.ERR, "error: ", err)
    return
end

local m
m, err = iterator()    -- m[0] == m[1] == "hello"
if err then
    ngx.log(ngx.ERR, "error: ", err)
    return
end

m, err = iterator()    -- m[0] == m[1] == "world"
if err then
    ngx.log(ngx.ERR, "error: ", err)
    return
end

m, err = iterator()    -- m == nil
if err then
    ngx.log(ngx.ERR, "error: ", err)
    return
end

Чаще всего мы просто используем его в цикле Lua:

local it, err = ngx.re.gmatch("hello, world!", "([a-z]+)", "i")
if not it then
    ngx.log(ngx.ERR, "error: ", err)
    return
end

while true do
    local m, err = it()
    if err then
        ngx.log(ngx.ERR, "error: ", err)
        return
    end

    if not m then
        -- no match found (any more)
        break
    end

    -- found a match
    ngx.say(m[0])
    ngx.say(m[1])
end

Необязательный аргумент options имеет точно такое же значение, как и в методе ngx.re.match.

Текущая реализация требует, чтобы возвращённый итератор использовался только в пределах одного запроса. То есть его нельзя присваивать переменной в постоянном пространстве имён, например в пакете Lua.

Для работы этого метода в Nginx должна быть включена библиотека PCRE (Известная проблема со специальными escape-последовательностями).

Эта возможность впервые появилась в выпуске v0.2.1rc12.

ngx.re.sub

синтаксис: newstr, n, err = ngx.re.sub(subject, regex, replace, options?)

контекст: init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, exit_worker_by_lua*, ssl_client_hello_by_lua*

Заменяет первое совпадение регулярного выражения regex, совместимого с Perl, в строковом аргументе subject строкой или функцией из аргумента replace. Необязательный аргумент options имеет точно такое же значение, как и в ngx.re.match.

Этот метод возвращает полученную новую строку, а также количество успешных замен. При ошибках, например при синтаксических ошибках в регулярных выражениях или строковом аргументе <replace>, он возвращает nil и строку с описанием ошибки.

Если replace является строкой, она интерпретируется как специальный шаблон для замены строк. Например,

local newstr, n, err = ngx.re.sub("hello, 1234", "([0-9])[0-9]", "[$0][$1]")
if not newstr then
    ngx.log(ngx.ERR, "error: ", err)
    return
end

-- newstr == "hello, [12][1]34"
-- n == 1

где $0 обозначает всю подстроку, совпавшую с шаблоном, а $1 — первую захваченную подстроку в круглых скобках.

Фигурные скобки также можно использовать, чтобы отделить имена переменных от следующих за ними строковых литералов:

local newstr, n, err = ngx.re.sub("hello, 1234", "[0-9]", "${0}00")
-- newstr == "hello, 100234"
-- n == 1

Литералы символа доллара ($) в строковом аргументе replace можно экранировать дополнительным символом доллара, например:

local newstr, n, err = ngx.re.sub("hello, 1234", "[0-9]", "$$")
-- newstr == "hello, $234"
-- n == 1

Не используйте обратную косую черту для экранирования символов доллара — это не даст ожидаемого результата.

Если аргумент replace имеет тип "function", он будет вызван с таблицей совпадений в качестве аргумента для формирования строкового литерала замены. Таблица совпадений, передаваемая функции replace, точно такая же, как значение, возвращаемое ngx.re.match. Пример:

local func = function (m)
    return "[" .. m[0] .. "][" .. m[1] .. "]"
end

local newstr, n, err = ngx.re.sub("hello, 1234", "( [0-9] ) [0-9]", func, "x")
-- newstr == "hello, [12][1]34"
-- n == 1

Символы доллара в значении, возвращаемом функциональным аргументом replace, не имеют специального значения.

Для работы этого метода в Nginx должна быть включена библиотека PCRE (Известная проблема со специальными escape-последовательностями).

Эта возможность впервые появилась в выпуске v0.2.1rc13.

ngx.re.gsub

синтаксис: newstr, n, err = ngx.re.gsub(subject, regex, replace, options?)

контекст: init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, exit_worker_by_lua*, ssl_client_hello_by_lua*

Работает так же, как ngx.re.sub, но выполняет глобальную замену.

Вот несколько примеров:

local newstr, n, err = ngx.re.gsub("hello, world", "([a-z])[a-z]+", "[$0,$1]", "i")
if not newstr then
    ngx.log(ngx.ERR, "error: ", err)
    return
end

-- newstr == "[hello,h], [world,w]"
-- n == 2
local func = function (m)
    return "[" .. m[0] .. "," .. m[1] .. "]"
end
local newstr, n, err = ngx.re.gsub("hello, world", "([a-z])[a-z]+", func, "i")
-- newstr == "[hello,h], [world,w]"
-- n == 2

Для этого метода требуется включённая в Nginx библиотека PCRE (Известная проблема со специальными последовательностями экранирования).

Эта функция впервые появилась в выпуске v0.2.1rc15.

ngx.shared.DICT

синтаксис: dict = ngx.shared.DICT

синтаксис: dict = ngx.shared[name_var]

контекст: init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, exit_worker_by_lua*, ssl_client_hello_by_lua*

Получение объекта словаря Lua на основе shm для зоны общей памяти с именем DICT, определённой директивой lua_shared_dict.

Зоны общей памяти всегда доступны всем рабочим процессам Nginx в текущем экземпляре сервера Nginx.

Полученный объект dict имеет следующие методы:

  • get
  • get_stale
  • set
  • safe_set
  • add
  • safe_add
  • replace
  • delete
  • incr
  • lpush
  • rpush
  • lpop
  • rpop
  • llen
  • ttl
  • expire
  • flush_all
  • flush_expired
  • get_keys
  • capacity
  • free_space

Все эти методы являются атомарными операциями, то есть защищены от одновременного доступа из нескольких рабочих процессов Nginx к одной и той же зоне lua_shared_dict.

Вот пример:

http {
    lua_shared_dict dogs 10m;
    server {
        location /set {
            content_by_lua_block {
                local dogs = ngx.shared.dogs
                dogs:set("Jim", 8)
                ngx.say("STORED")
            }
        }
        location /get {
            content_by_lua_block {
                local dogs = ngx.shared.dogs
                ngx.say(dogs:get("Jim"))
            }
        }
    }
}

Проверим это:

$ curl localhost/set
STORED

$ curl localhost/get
8

$ curl localhost/get
8

При обращении к /get будет стабильно выводиться число 8 независимо от количества рабочих процессов Nginx, поскольку словарь dogs находится в общей памяти и доступен всем рабочим процессам.

Содержимое общего словаря сохраняется при перезагрузке конфигурации сервера (как при отправке процессу Nginx сигнала HUP, так и при использовании параметра командной строки -s reload).

Однако содержимое хранилища словаря будет утрачено при завершении работы сервера Nginx.

Эта функция впервые появилась в выпуске v0.3.1rc22.

ngx.shared.DICT.get

синтаксис: value, flags = ngx.shared.DICT:get(key)

контекст: set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, ssl_client_hello_by_lua*

Получение значения из словаря ngx.shared.DICT по ключу key. Если ключ не существует или срок его действия истёк, будет возвращено nil.

В случае ошибки возвращаются nil и строка с описанием ошибки.

Возвращаемое значение сохраняет исходный тип данных, имевшийся при добавлении в словарь, например, логическое значение Lua, число или строку.

Первым аргументом этого метода должен быть сам объект словаря, например:

local cats = ngx.shared.cats
local value, flags = cats.get(cats, "Marry")

или можно использовать синтаксический сахар Lua для вызова методов:

local cats = ngx.shared.cats
local value, flags = cats:get("Marry")

Эти две формы по существу эквивалентны.

Если пользовательские флаги равны 0 (значение по умолчанию), значение флагов возвращено не будет.

Эта функция впервые появилась в выпуске v0.3.1rc22.

См. также ngx.shared.DICT.

ngx.shared.DICT.get_stale

синтаксис: value, flags, stale = ngx.shared.DICT:get_stale(key)

контекст: set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, ssl_client_hello_by_lua*

Работает аналогично методу get, но возвращает значение, даже если срок действия ключа уже истёк.

Возвращает третье значение, stale, указывающее, истёк ли срок действия ключа.

Обратите внимание: наличие значения для ключа с истёкшим сроком действия не гарантируется, поэтому не следует полагаться на доступность просроченных элементов.

Этот метод впервые появился в выпуске 0.8.6.

См. также ngx.shared.DICT.

ngx.shared.DICT.set

синтаксис: success, err, forcible = ngx.shared.DICT:set(key, value, exptime?, flags?)

контекст: init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, ssl_client_hello_by_lua*

Безусловно записывает пару «ключ-значение» в словарь ngx.shared.DICT на основе shm. Возвращает три значения:

  • success: логическое значение, указывающее, была ли сохранена пара «ключ-значение».
  • err: текстовое сообщение об ошибке; может быть равно "no memory".
  • forcible: логическое значение, указывающее, были ли принудительно удалены другие действительные элементы из-за нехватки места в зоне общей памяти.

В качестве аргумента value можно передать логические значения Lua, числа, строки или nil. Тип значения также сохраняется в словаре, и позднее его можно получить с тем же типом данных с помощью метода get.

Необязательный аргумент exptime задаёт время истечения срока действия (в секундах) для добавляемой пары «ключ-значение». Точность времени составляет 0.001 секунды. Если аргумент exptime имеет значение 0 (по умолчанию), срок действия элемента никогда не истечёт.

Необязательный аргумент flags задаёт пользовательское значение флагов, связанное с сохраняемой записью. Позднее его также можно получить вместе со значением. Внутри пользовательские флаги хранятся как 32-разрядное беззнаковое целое число. По умолчанию используется 0. Аргумент пользовательских флагов впервые появился в выпуске v0.5.0rc2.

Если не удаётся выделить память для текущей пары «ключ-значение», set попытается удалить существующие элементы хранилища согласно алгоритму вытеснения наименее недавно использовавшихся (LRU). Обратите внимание: в данном случае LRU имеет приоритет над временем истечения срока действия. Если даже после удаления до нескольких десятков существующих элементов свободного места всё ещё недостаточно (из-за ограничения общей ёмкости, заданного директивой lua_shared_dict, или фрагментации памяти), возвращаемое значение err будет равно no memory, а success будет равно false.

Если размеры элементов в словаре не кратны некоторому значению и не являются его целыми степенями (например, степени числа 2), ошибка no memory может возникать чаще из-за фрагментации памяти. Рекомендуется использовать разные словари для элементов разных размеров.

При возникновении ошибки no memory можно вытеснить больше наименее недавно использовавшихся элементов, повторив вызов этого метода несколько раз, чтобы освободить место для текущего элемента.

Если метод успешно сохраняет текущий элемент, принудительно удаляя другие элементы с неистёкшим сроком действия посредством LRU, возвращаемое значение forcible будет равно true. Если элемент сохраняется без принудительного удаления других действительных элементов, возвращаемое значение forcible будет равно false.

Первым аргументом этого метода должен быть сам объект словаря, например:

local cats = ngx.shared.cats
local succ, err, forcible = cats.set(cats, "Marry", "it is a nice cat!")

или можно использовать синтаксический сахар Lua для вызова методов:

local cats = ngx.shared.cats
local succ, err, forcible = cats:set("Marry", "it is a nice cat!")

Эти две формы по существу эквивалентны.

Эта функция впервые появилась в выпуске v0.3.1rc22.

Обратите внимание: хотя внутри пара «ключ-значение» устанавливается атомарно, атомарность не распространяется на границы вызова метода.

См. также ngx.shared.DICT.

ngx.shared.DICT.safe_set

синтаксис: ok, err = ngx.shared.DICT:safe_set(key, value, exptime?, flags?)

контекст: init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, ssl_client_hello_by_lua*

Работает аналогично методу set, но при нехватке места в зоне общей памяти никогда не перезаписывает неистёкшие элементы хранилища (с наименее недавним использованием). В этом случае метод немедленно возвращает nil и строку "no memory".

Эта функция впервые появилась в выпуске v0.7.18.

См. также ngx.shared.DICT.

ngx.shared.DICT.add

синтаксис: success, err, forcible = ngx.shared.DICT:add(key, value, exptime?, flags?)

контекст: init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, ssl_client_hello_by_lua*

Работает аналогично методу set, но записывает пару «ключ-значение» в словарь ngx.shared.DICT только в том случае, если ключ не существует.

Если аргумент key уже существует в словаре (и его срок действия точно не истёк), возвращаемое значение success будет равно false, а возвращаемое значение err будет равно "exists".

Эта функция впервые появилась в выпуске v0.3.1rc22.

См. также ngx.shared.DICT.

ngx.shared.DICT.safe_add

синтаксис: ok, err = ngx.shared.DICT:safe_add(key, value, exptime?, flags?)

контекст: init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, ssl_client_hello_by_lua*

Работает аналогично методу add, но при нехватке места в зоне общей памяти никогда не перезаписывает неистёкшие элементы хранилища (с наименее недавним использованием). В этом случае метод немедленно возвращает nil и строку "no memory".

Эта функция впервые появилась в выпуске v0.7.18.

См. также ngx.shared.DICT.

ngx.shared.DICT.replace

синтаксис: success, err, forcible = ngx.shared.DICT:replace(key, value, exptime?, flags?)

контекст: init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, ssl_client_hello_by_lua*

Работает аналогично методу set, но записывает пару «ключ-значение» в словарь ngx.shared.DICT только в том случае, если ключ существует.

Если аргумент key не существует в словаре (или срок его действия уже истёк), возвращаемое значение success будет равно false, а возвращаемое значение err будет равно "not found".

Эта функция впервые появилась в выпуске v0.3.1rc22.

См. также ngx.shared.DICT.

ngx.shared.DICT.delete

синтаксис: ngx.shared.DICT:delete(key)

контекст: init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, ssl_client_hello_by_lua*

Безусловно удаляет пару «ключ-значение» из словаря ngx.shared.DICT на основе shm.

Это эквивалентно ngx.shared.DICT:set(key, nil).

Эта функция впервые появилась в выпуске v0.3.1rc22.

См. также ngx.shared.DICT.

ngx.shared.DICT.incr

синтаксис: newval, err, forcible? = ngx.shared.DICT:incr(key, value, init?, init_ttl?)

контекст: init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, ssl_client_hello_by_lua*

необязательное требование: resty.core.shdict или resty.core

Увеличивает числовое значение для key в словаре ngx.shared.DICT на основе shm на величину шага value. Если операция выполнена успешно, возвращает новое значение; в противном случае возвращает nil и сообщение об ошибке.

Если ключ не существует в общем словаре или срок его действия уже истёк:

  1. если аргумент init не указан или имеет значение nil, метод вернёт nil и строку ошибки "not found"; либо
  2. если аргумент init имеет числовое значение, метод создаст новый key со значением init + value.

Как и метод add, при нехватке места в зоне общей памяти он также перезаписывает неистёкшие элементы хранилища (с наименее недавним использованием).

Необязательный аргумент init_ttl задаёт время истечения срока действия (в секундах) значения, инициализированного с помощью аргумента init. Точность времени составляет 0.001 секунды. Если init_ttl имеет значение 0 (по умолчанию), срок действия элемента никогда не истечёт. Этот аргумент нельзя указывать без аргумента init; он не влияет на значение, которое уже существует (например, если оно ранее было добавлено с помощью set или аналогичного метода).

Примечание: Для использования аргумента init_ttl необходимы модули resty.core.shdict или resty.core из библиотеки lua-resty-core. Пример:

require "resty.core"

local cats = ngx.shared.cats
local newval, err = cats:incr("black_cats", 1, 0, 0.1)

print(newval) -- 1

ngx.sleep(0.2)

local val, err = cats:get("black_cats")
print(val) -- nil

Возвращаемое значение forcible всегда будет равно nil, если аргумент init не указан.

Если метод успешно сохраняет текущий элемент, принудительно удаляя другие элементы с неистёкшим сроком действия посредством LRU, возвращаемое значение forcible будет равно true. Если элемент сохраняется без принудительного удаления других действительных элементов, возвращаемое значение forcible будет равно false.

Если исходное значение в словаре не является допустимым числом Lua, метод вернёт nil и "not a number".

Аргументы value и init могут быть любыми допустимыми числами Lua, например отрицательными числами или числами с плавающей точкой.

Этот метод впервые появился в выпуске v0.3.1rc22.

Необязательный параметр init впервые появился в выпуске v0.10.6.

Необязательный параметр init_ttl появился в выпуске v0.10.12rc2.

См. также ngx.shared.DICT.

ngx.shared.DICT.lpush

синтаксис: length, err = ngx.shared.DICT:lpush(key, value)

контекст: init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, ssl_client_hello_by_lua*

Вставляет указанное value (числовое или строковое) в начало списка с именем key в словаре ngx.shared.DICT на основе shm. Возвращает количество элементов в списке после операции добавления.

Если key не существует, перед добавлением он создаётся как пустой список. Если key уже имеет значение, не являющееся списком, метод вернёт nil и "value not a list".

При нехватке места в зоне общей памяти метод никогда не перезаписывает неистёкшие элементы хранилища (с наименее недавним использованием). В этом случае он немедленно возвращает nil и строку "no memory".

Эта функция впервые появилась в выпуске v0.10.6.

См. также ngx.shared.DICT.

ngx.shared.DICT.rpush

синтаксис: length, err = ngx.shared.DICT:rpush(key, value)

контекст: init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, ssl_client_hello_by_lua*

Работает аналогично методу lpush, но вставляет указанное value (числовое или строковое) в конец списка с именем key.

Эта функция впервые появилась в выпуске v0.10.6.

См. также ngx.shared.DICT.

ngx.shared.DICT.lpop

синтаксис: val, err = ngx.shared.DICT:lpop(key)

контекст: init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, ssl_client_hello_by_lua*

Удаляет и возвращает первый элемент списка с именем key в словаре ngx.shared.DICT на основе shm.

Если key не существует, метод вернёт nil. Если key уже имеет значение, не являющееся списком, метод вернёт nil и "value not a list".

Эта функция впервые появилась в выпуске v0.10.6.

См. также ngx.shared.DICT.

ngx.shared.DICT.rpop

синтаксис: val, err = ngx.shared.DICT:rpop(key)

контекст: init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, ssl_client_hello_by_lua*

Удаляет и возвращает последний элемент списка с именем key в словаре ngx.shared.DICT на основе shm.

Если key не существует, метод вернёт nil. Если key уже имеет значение, не являющееся списком, метод вернёт nil и "value not a list".

Эта функция впервые появилась в выпуске v0.10.6.

См. также ngx.shared.DICT.

ngx.shared.DICT.llen

синтаксис: len, err = ngx.shared.DICT:llen(key)

контекст: init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, ssl_client_hello_by_lua*

Возвращает количество элементов в списке с именем key в словаре ngx.shared.DICT на основе shm.

Если ключ не существует, он считается пустым списком, и возвращается 0. Если key уже имеет значение, не являющееся списком, метод вернёт nil и "value not a list".

Эта функция впервые появилась в выпуске v0.10.6.

См. также ngx.shared.DICT.

ngx.shared.DICT.ttl

синтаксис: ttl, err = ngx.shared.DICT:ttl(key)

контекст: init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, ssl_client_hello_by_lua*

требуется: resty.core.shdict или resty.core

Получает оставшееся время жизни (TTL, в секундах) пары «ключ-значение» в словаре ngx.shared.DICT на основе shm. Если операция выполнена успешно, возвращает TTL в виде числа; в противном случае возвращает nil и сообщение об ошибке.

Если ключ не существует (или срок его действия уже истёк), метод вернёт nil и строку ошибки "not found".

Исходный TTL задаётся аргументом exptime методов set, add, replace и подобных. Точность времени составляет 0.001 секунды. Значение 0 означает, что срок действия элемента никогда не истечёт.

Пример:

require "resty.core"

local cats = ngx.shared.cats
local succ, err = cats:set("Marry", "a nice cat", 0.5)

ngx.sleep(0.2)

local ttl, err = cats:ttl("Marry")
ngx.say(ttl) -- 0.3

Эта функция впервые появилась в выпуске v0.10.11.

Примечание: Для этого метода необходимы модули resty.core.shdict или resty.core из библиотеки lua-resty-core.

См. также ngx.shared.DICT.

ngx.shared.DICT.expire

синтаксис: success, err = ngx.shared.DICT:expire(key, exptime)

контекст: init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, ssl_client_hello_by_lua*

требуется: resty.core.shdict или resty.core

Обновляет exptime (в секундах) пары «ключ-значение» в словаре ngx.shared.DICT на основе shm. Если операция выполнена успешно, возвращает логическое значение, указывающее на успех; в противном случае возвращает nil и сообщение об ошибке.

Если ключ не существует, метод вернёт nil и строку ошибки "not found".

Точность аргумента exptime составляет 0.001 секунды. Если exptime равно 0, срок действия элемента никогда не истечёт.

Пример:

require "resty.core"

local cats = ngx.shared.cats
local succ, err = cats:set("Marry", "a nice cat", 0.1)

succ, err = cats:expire("Marry", 0.5)

ngx.sleep(0.2)

local val, err = cats:get("Marry")
ngx.say(val) -- "a nice cat"

Эта функция впервые появилась в выпуске v0.10.11.

Примечание: Для этого метода необходимы модули resty.core.shdict или resty.core из библиотеки lua-resty-core.

См. также ngx.shared.DICT.

ngx.shared.DICT.flush_all

синтаксис: ngx.shared.DICT:flush_all()

контекст: init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, ssl_client_hello_by_lua*

Удаляет все элементы из словаря. Этот метод фактически не освобождает все блоки памяти в словаре, а только помечает все существующие элементы как просроченные.

Эта функция впервые появилась в выпуске v0.5.0rc17.

См. также ngx.shared.DICT.flush_expired и ngx.shared.DICT.

ngx.shared.DICT.flush_expired

синтаксис: flushed = ngx.shared.DICT:flush_expired(max_count?)

контекст: init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, ssl_client_hello_by_lua*

Удаляет просроченные элементы из словаря, не превышая максимального количества, заданного необязательным аргументом max_count. Если аргумент max_count равен 0 или не указан, количество не ограничивается. Возвращает число фактически удалённых элементов.

В отличие от метода flush_all, этот метод действительно освобождает память, занятую просроченными элементами.

Эта возможность впервые появилась в выпуске v0.6.3.

См. также ngx.shared.DICT.flush_all и ngx.shared.DICT.

ngx.shared.DICT.get_keys

синтаксис: keys = ngx.shared.DICT:get_keys(max_count?)

контекст: init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, ssl_client_hello_by_lua*

Возвращает список ключей из словаря, не более <max_count>.

По умолчанию возвращаются только первые 1024 ключа (если они есть). Если аргумент <max_count> задан со значением 0, будут возвращены все ключи, даже если в словаре их больше 1024.

ВНИМАНИЕ Не вызывайте этот метод для словарей с очень большим количеством ключей: он может надолго заблокировать словарь и блокировать рабочие процессы Nginx, пытающиеся получить к нему доступ.

Эта возможность впервые появилась в выпуске v0.7.3.

ngx.shared.DICT.capacity

синтаксис: capacity_bytes = ngx.shared.DICT:capacity()

контекст: init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, ssl_client_hello_by_lua*

требуется: resty.core.shdict или resty.core

Возвращает емкость в байтах словаря ngx.shared.DICT на основе общей памяти, объявленного с помощью директивы lua_shared_dict.

Пример:

require "resty.core.shdict"

local cats = ngx.shared.cats
local capacity_bytes = cats:capacity()

Эта возможность впервые появилась в выпуске v0.10.11.

Примечание: Для этого метода требуются модули resty.core.shdict или resty.core из библиотеки lua-resty-core.

Для этой возможности требуется версия ядра Nginx не ниже 0.7.3.

См. также ngx.shared.DICT.

ngx.shared.DICT.free_space

синтаксис: free_page_bytes = ngx.shared.DICT:free_space()

контекст: init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, ssl_client_hello_by_lua*

требуется: resty.core.shdict или resty.core

Возвращает размер свободного пространства в страницах в байтах для словаря ngx.shared.DICT на основе общей памяти.

Примечание: Память для ngx.shared.DICT выделяется с помощью распределителя Nginx slab, в котором для каждого слота предусмотрены диапазоны размеров данных: ~8, 9~16, 17~32, ..., 1025~2048, 2048~ байт. Страницы назначаются слоту, если в уже назначенных ему страницах нет места.

Поэтому, даже если значение, возвращаемое методом free_space, равно нулю, в уже назначенных страницах может оставаться место, и тогда можно успешно добавить в общий словарь пару «ключ-значение», не получив true для forcible или ненулевое значение err из метода ngx.shared.DICT.set.

С другой стороны, если уже назначенные слоту страницы заполнены, а в слот добавляется новая пара «ключ-значение» и свободных страниц нет, можно получить true для forcible или ненулевое значение err из метода ngx.shared.DICT.set.

Пример:

require "resty.core.shdict"

local cats = ngx.shared.cats
local free_page_bytes = cats:free_space()

Эта возможность впервые появилась в выпуске v0.10.11.

Примечание: Для этого метода требуются модули resty.core.shdict или resty.core из библиотеки lua-resty-core.

Для этой возможности требуется версия ядра Nginx не ниже 1.11.7.

См. также ngx.shared.DICT.

ngx.socket.udp

синтаксис: udpsock = ngx.socket.udp()

контекст: rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_client_hello_by_lua*

Создает и возвращает объект UDP-сокета или сокета домена Unix для датаграмм (также известный как один из типов объектов «cosocket»). Для этого объекта поддерживаются следующие методы:

  • bind
  • setpeername
  • send
  • receive
  • close
  • settimeout

Предполагается совместимость с API UDP библиотеки LuaSocket, но из коробки он на 100% неблокирующий.

Эта возможность впервые появилась в выпуске v0.5.7.

См. также ngx.socket.tcp.

udpsock:bind

синтаксис: ok, err = udpsock:bind(address)

контекст: rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*,ssl_session_fetch_by_lua*,ssl_client_hello_by_lua*

Как и стандартная директива proxy_bind, этот API позволяет исходящему соединению с вышестоящим сервером устанавливаться с указанного локального IP-адреса.

В качестве аргумента address можно указать только IP-адреса.

Пример подключения к TCP-серверу с указанного локального IP-адреса:

location /test {
    content_by_lua_block {
        local sock = ngx.socket.udp()
        -- assume "192.168.1.10" is the local ip address
        local ok, err = sock:bind("192.168.1.10")
        if not ok then
            ngx.say("failed to bind: ", err)
            return
        end
        sock:close()
    }
}

udpsock:setpeername

синтаксис: ok, err = udpsock:setpeername(host, port)

синтаксис: ok, err = udpsock:setpeername("unix:/path/to/unix-domain.socket")

контекст: rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_client_hello_by_lua*

Пытается подключить объект UDP-сокета к удаленному серверу или файлу сокета домена Unix для датаграмм. Поскольку протокол датаграмм фактически не ориентирован на соединения, этот метод не устанавливает настоящее «соединение», а лишь задает имя удаленного узла для последующих операций чтения и записи.

В качестве аргумента host можно указать IP-адреса и доменные имена. Для доменных имен этот метод использует динамический резолвер ядра Nginx для разрешения имени без блокировки. Для этого необходимо настроить директиву resolver в файле nginx.conf, например:

resolver 8.8.8.8;  # use Google's public DNS nameserver

Если сервер имен возвращает для имени хоста несколько IP-адресов, метод случайным образом выберет один из них.

В случае ошибки метод возвращает nil, за которым следует строка с описанием ошибки. В случае успеха метод возвращает 1.

Пример подключения к UDP-серверу (memcached):

location /test {
    resolver 8.8.8.8;

    content_by_lua_block {
        local sock = ngx.socket.udp()
        local ok, err = sock:setpeername("my.memcached.server.domain", 11211)
        if not ok then
            ngx.say("failed to connect to memcached: ", err)
            return
        end
        ngx.say("successfully connected to memcached!")
        sock:close()
    }
}

Начиная с выпуска v0.7.18, в Linux также можно подключаться к файлу сокета домена Unix для датаграмм:

local sock = ngx.socket.udp()
local ok, err = sock:setpeername("unix:/tmp/some-datagram-service.sock")
if not ok then
    ngx.say("failed to connect to the datagram unix domain socket: ", err)
    return
end

-- do something after connect
-- such as sock:send or sock:receive

при условии, что служба датаграмм прослушивает файл сокета домена Unix /tmp/some-datagram-service.sock, а клиентский сокет использует в Linux функцию «autobind».

Вызов этого метода для уже подключенного объекта сокета сначала закроет исходное соединение.

Этот метод впервые появился в выпуске v0.5.7.

udpsock:send

синтаксис: ok, err = udpsock:send(data)

контекст: rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_client_hello_by_lua*

Отправляет данные через текущий объект UDP-сокета или сокета домена Unix для датаграмм.

В случае успеха возвращает 1. В противном случае возвращает nil и строку с описанием ошибки.

Входной аргумент data может быть строкой Lua или (вложенной) таблицей Lua со строковыми фрагментами. Если аргументом является таблица, метод по частям копирует все строковые элементы в буферы отправки сокета Nginx. Обычно это эффективнее, чем конкатенация строк на стороне Lua.

Эта возможность впервые появилась в выпуске v0.5.7.

udpsock:receive

синтаксис: data, err = udpsock:receive(size?)

контекст: rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_client_hello_by_lua*

Получает данные из объекта UDP-сокета или сокета домена Unix для датаграмм. Можно указать необязательный аргумент, задающий размер буфера приема: size.

Этот метод выполняется синхронно и на 100% неблокирующий.

В случае успеха он возвращает полученные данные; в случае ошибки — nil и строку с описанием ошибки.

Если указан аргумент size, метод использует его значение как размер буфера приема. Если это значение превышает 8192, вместо него будет использовано 8192.

Если аргумент не указан, предполагается максимальный размер буфера — 8192.

Время ожидания операции чтения задается директивой конфигурации lua_socket_read_timeout и методом settimeout. Приоритет имеет последний. Например:

sock:settimeout(1000)  -- one second timeout
local data, err = sock:receive()
if not data then
    ngx.say("failed to read a packet: ", err)
    return
end
ngx.say("successfully read a packet: ", data)

Важно вызвать метод settimeout до вызова этого метода.

Эта возможность впервые появилась в выпуске v0.5.7.

udpsock:close

синтаксис: ok, err = udpsock:close()

контекст: rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_client_hello_by_lua*

Закрывает текущий UDP-сокет или сокет домена Unix для датаграмм. В случае успеха возвращает 1, а в противном случае возвращает nil и строку с описанием ошибки.

Объекты сокетов, для которых этот метод не был вызван (и связанные с ними соединения), будут закрыты, когда объект сокета будет освобожден сборщиком мусора Lua или завершится обработка текущего HTTP-запроса клиента.

Эта возможность впервые появилась в выпуске v0.5.7.

udpsock:settimeout

синтаксис: udpsock:settimeout(time)

контекст: rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_client_hello_by_lua*

Задает время ожидания в миллисекундах для последующих операций с сокетом (например, receive).

Настройки, заданные этим методом, имеют приоритет над директивами конфигурации, например lua_socket_read_timeout.

Эта возможность впервые появилась в выпуске v0.5.7.

ngx.socket.stream

Просто псевдоним для ngx.socket.tcp. Если cosocket потокового типа также может подключаться к сокету домена Unix, предпочтительно использовать это имя API.

Эта функция API впервые появилась в выпуске v0.10.1.

ngx.socket.tcp

синтаксис: tcpsock = ngx.socket.tcp()

контекст: rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_client_hello_by_lua*

Создает и возвращает объект TCP-сокета или потокового сокета домена Unix (также известный как один из типов объектов «cosocket»). Для этого объекта поддерживаются следующие методы:

  • bind
  • connect
  • setclientcert
  • sslhandshake
  • send
  • receive
  • close
  • settimeout
  • settimeouts
  • setoption
  • receiveany
  • receiveuntil
  • setkeepalive
  • getreusedtimes

Предполагается совместимость с TCP API библиотеки LuaSocket, но из коробки он на 100% неблокирующий. Кроме того, мы добавили новые API для расширения функциональности.

Объект cosocket, созданный этой функцией API, существует ровно столько же, сколько Lua-обработчик, который его создал. Поэтому никогда не передавайте объект cosocket другому Lua-обработчику (включая функции обратного вызова ngx.timer) и не используйте один объект cosocket совместно для разных запросов Nginx.

Если для базового соединения объекта cosocket явно не вызвать close или не вернуть его в пул соединений с помощью setkeepalive, соединение будет закрыто автоматически при наступлении одного из следующих событий:

  • завершение обработки текущего запроса или
  • сборка объекта cosocket сборщиком мусора Lua.

Фатальные ошибки при операциях с cosocket всегда автоматически закрывают текущее соединение (обратите внимание: ошибка тайм-аута чтения — единственная нефинальная ошибка). Если вызвать close для закрытого соединения, будет возвращена ошибка «closed».

Начиная с выпуска 0.9.9 объект cosocket является полнодуплексным: поток чтения и «легкий поток» записи могут одновременно работать с одним объектом cosocket (однако оба «легких потока» должны принадлежать одному Lua-обработчику; см. причины выше). Но два «легких потока» не могут одновременно читать (или записывать, или подключаться) через один и тот же cosocket, иначе при вызове его методов может возникнуть ошибка, например «socket busy reading».

Эта возможность впервые появилась в выпуске v0.5.0rc1.

См. также ngx.socket.udp.

tcpsock:bind

синтаксис: ok, err = tcpsock:bind(address)

контекст: rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*,ssl_session_fetch_by_lua*,ssl_client_hello_by_lua*

Как и стандартная директива proxy_bind, этот API позволяет исходящему соединению с вышестоящим сервером устанавливаться с указанного локального IP-адреса.

В качестве аргумента address можно указать только IP-адреса.

Пример подключения к TCP-серверу с указанного локального IP-адреса:

location /test {
    content_by_lua_block {
        local sock = ngx.socket.tcp()
        -- assume "192.168.1.10" is the local ip address
        local ok, err = sock:bind("192.168.1.10")
        if not ok then
            ngx.say("failed to bind")
            return
        end
        local ok, err = sock:connect("192.168.1.67", 80)
        if not ok then
            ngx.say("failed to connect server: ", err)
            return
        end
        ngx.say("successfully connected!")
        sock:close()
    }
}

tcpsock:connect

синтаксис: ok, err = tcpsock:connect(host, port, options_table?)

синтаксис: ok, err = tcpsock:connect("unix:/path/to/unix-domain.socket", options_table?)

контекст: rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_client_hello_by_lua*

Пытается без блокировки подключить объект TCP-сокета к удаленному серверу или файлу потокового сокета домена Unix.

Прежде чем разрешать имя хоста и подключаться к удаленному серверу, этот метод всегда ищет в пуле соединений подходящие простаивающие соединения, созданные предыдущими вызовами этого метода (или функции ngx.socket.connect).

В качестве аргумента host можно указать IP-адреса и доменные имена. Для доменных имен этот метод использует динамический резолвер ядра Nginx для разрешения имени без блокировки. Для этого необходимо настроить директиву resolver в файле nginx.conf, например:

resolver 8.8.8.8;  # use Google's public DNS nameserver

Если сервер имен возвращает для имени хоста несколько IP-адресов, метод случайным образом выберет один из них.

В случае ошибки метод возвращает nil, за которым следует строка с описанием ошибки. В случае успеха метод возвращает 1.

Пример подключения к TCP-серверу:

location /test {
    resolver 8.8.8.8;

    content_by_lua_block {
        local sock = ngx.socket.tcp()
        local ok, err = sock:connect("www.google.com", 80)
        if not ok then
            ngx.say("failed to connect to google: ", err)
            return
        end
        ngx.say("successfully connected to google!")
        sock:close()
    }
}

Также возможно подключение к файлу сокета домена Unix:

local sock = ngx.socket.tcp()
local ok, err = sock:connect("unix:/tmp/memcached.sock")
if not ok then
    ngx.say("failed to connect to the memcached unix domain socket: ", err)
    return
end

-- do something after connect
-- such as sock:send or sock:receive

при условии, что memcached (или другая служба) прослушивает файл сокета домена Unix /tmp/memcached.sock.

Время ожидания операции подключения задается директивой конфигурации lua_socket_connect_timeout и методом settimeout. Приоритет имеет последний. Например:

local sock = ngx.socket.tcp()
sock:settimeout(1000)  -- one second timeout
local ok, err = sock:connect(host, port)

Важно вызвать метод settimeout до вызова этого метода.

Вызов этого метода для уже подключенного объекта сокета сначала закроет исходное соединение.

В качестве последнего аргумента этого метода можно указать необязательную таблицу Lua, чтобы задать различные параметры подключения:

  • pool задает пользовательское имя используемого пула соединений. Если параметр не указан, имя пула соединений будет сформировано по шаблону строки "<host>:<port>" или "<unix-socket-path>".

  • pool_size задает размер пула соединений. Если параметр не указан и параметр backlog не задан, пул создаваться не будет. Если параметр не указан, но задан backlog, пул будет создан с размером по умолчанию, равным значению директивы lua_socket_pool_size. Пул соединений хранит до pool_size активных соединений, готовых к повторному использованию при последующих вызовах connect. Однако общее число открытых соединений вне пула не ограничено. Чтобы ограничить общее число открытых соединений, укажите параметр backlog. Если размер пула превысит установленный предел, наименее недавно использовавшееся соединение (находящееся в состоянии keep-alive), уже находящееся в пуле, будет закрыто, чтобы освободить место для текущего соединения. Обратите внимание, что пул соединений cosocket создается для каждого рабочего процесса Nginx, а не для экземпляра сервера Nginx, поэтому указанный здесь предел размера применяется к каждому рабочему процессу Nginx. Также обратите внимание, что размер пула соединений нельзя изменить после его создания. Этот параметр впервые появился в выпуске v0.10.14.

  • backlog при указании этого параметра модуль ограничивает общее число открытых соединений для данного пула. Одновременно для пула может быть открыто не более pool_size соединений. Если pool_size соединений уже используются, последующие операции подключения будут помещены в очередь, размер которой равен значению этого параметра (очередь «backlog»). Если число операций подключения в очереди равно backlog, последующие операции подключения завершатся ошибкой и вернут nil вместе со строкой ошибки "too many waiting connect operations". Операции подключения в очереди возобновятся, когда число активных соединений станет меньше pool_size. Операция подключения в очереди будет прервана, если она простоит в очереди дольше connect_timeout; это время задается методом settimeouts. В этом случае метод вернет nil вместе со строкой ошибки "timeout". Этот параметр впервые появился в выпуске v0.10.14.

Поддержка аргумента-таблицы параметров впервые появилась в выпуске v0.5.7.

Этот метод впервые появился в выпуске v0.5.0rc1.

tcpsock:setclientcert

синтаксис: ok, err = tcpsock:setclientcert(cert, pkey)

контекст: rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_client_hello_by_lua*

Задает цепочку сертификатов клиента и соответствующий закрытый ключ для объекта TCP-сокета. Переданные цепочка сертификатов и закрытый ключ будут использоваться позднее методом tcpsock:sslhandshake.

  • cert задает объект cdata цепочки сертификатов клиента, который будет использоваться при рукопожатии с удаленным сервером. Эти объекты можно создать с помощью функций ngx.ssl.parse_pem_cert или ngx.ssl.parse_der_cert, предоставляемых lua-resty-core. Обратите внимание: при указании параметра cert также необходимо передать соответствующий pkey. См. ниже.
  • pkey задает закрытый ключ, соответствующий указанному выше параметру cert. Эти объекты можно создать с помощью функций ngx.ssl.parse_pem_priv_key или ngx.ssl.parse_der_priv_key, предоставляемых lua-resty-core.

Если оба параметра cert и pkey имеют значение nil, этот метод удалит ранее заданные для объекта cosocket сертификат клиента и закрытый ключ.

Этот метод впервые появился в выпуске v0.10.22.

tcpsock:sslhandshake

синтаксис: session, err = tcpsock:sslhandshake(reused_session?, server_name?, ssl_verify?, send_status_req?)

контекст: rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_client_hello_by_lua*

Выполняет рукопожатие SSL/TLS для уже установленного соединения.

Необязательный аргумент reused_session может принимать userdata SSL-сессии, возвращенную предыдущим вызовом sslhandshake для того же целевого узла. Для короткоживущих соединений повторное использование SSL-сессий обычно позволяет ускорить рукопожатие на порядок, но при включенном пуле соединений это не так полезно. По умолчанию этот аргумент равен nil. Если аргумент имеет логическое значение false, этот вызов не возвращает userdata SSL-сессии, а первым возвращаемым значением будет только логическое значение Lua; в противном случае при успешном выполнении текущая SSL-сессия всегда возвращается в качестве первого аргумента.

Необязательный аргумент server_name задает имя сервера для нового расширения TLS Server Name Indication (SNI). Благодаря SNI на стороне сервера разные серверы могут использовать один IP-адрес. Кроме того, если включена проверка SSL, аргумент server_name используется для проверки имени сервера, указанного в сертификате, полученном от удаленного узла.

Необязательный аргумент ssl_verify принимает логическое значение Lua, определяющее, выполнять ли проверку SSL. Если задано значение true, сертификат сервера проверяется с использованием сертификатов центра сертификации, указанных директивой lua_ssl_trusted_certificate. Возможно, потребуется также настроить директиву lua_ssl_verify_depth, чтобы задать глубину проверки цепочки сертификатов. Кроме того, если аргумент ssl_verify имеет значение true и также указан аргумент server_name, последний будет использоваться для проверки имени сервера в сертификате.

Необязательный аргумент send_status_req принимает логическое значение, определяющее, отправлять ли в запросе на рукопожатие SSL запрос статуса OCSP (для запроса OCSP stapling).

Для соединений, в которых рукопожатие SSL/TLS уже выполнено, этот метод возвращает результат немедленно.

Этот метод впервые появился в выпуске v0.9.11.

tcpsock:send

синтаксис: bytes, err = tcpsock:send(data)

контекст: rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_client_hello_by_lua*

Отправляет данные через текущее соединение TCP или сокета домена Unix без блокировки.

Этот метод выполняется синхронно и не возвращает управление, пока все данные не будут переданы в системный буфер отправки сокета или пока не произойдет ошибка.

В случае успеха возвращает общее число отправленных байтов. В противном случае возвращает nil и строку с описанием ошибки.

Входной аргумент data может быть строкой Lua или (вложенной) таблицей Lua со строковыми фрагментами. Если аргументом является таблица, метод по частям копирует все строковые элементы в буферы отправки сокета Nginx. Обычно это эффективнее, чем конкатенация строк на стороне Lua.

Время ожидания операции отправки задается директивой конфигурации lua_socket_send_timeout и методом settimeout. Приоритет имеет последний. Например:

sock:settimeout(1000)  -- one second timeout
local bytes, err = sock:send(request)

Важно вызвать метод settimeout до вызова этого метода.

При любых ошибках соединения этот метод всегда автоматически закрывает текущее соединение.

Эта возможность впервые появилась в выпуске v0.5.0rc1.

tcpsock:receive

синтаксис: data, err, partial = tcpsock:receive(size)

синтаксис: data, err, partial = tcpsock:receive(pattern?)

контекст: rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_client_hello_by_lua*

Получает данные из подключенного сокета в соответствии с шаблоном чтения или заданным размером.

Этот метод является синхронной операцией, как и метод send, и на 100% не блокирует выполнение.

В случае успеха возвращает полученные данные; в случае ошибки возвращает nil со строкой, описывающей ошибку, и уже полученными частичными данными.

Если указан аргумент, похожий на число (включая строки, которые выглядят как числа), он интерпретируется как размер. Метод не вернёт результат, пока не прочитает данные точно такого размера или не произойдёт ошибка.

Если указан строковый аргумент, не похожий на число, он интерпретируется как «шаблон». Поддерживаются следующие шаблоны:

  • '*a': читает данные из сокета до закрытия соединения. Перевод символов конца строки не выполняется;
  • '*l': читает строку текста из сокета. Строка завершается символом Line Feed (LF) (ASCII 10), которому может предшествовать символ Carriage Return (CR) (ASCII 13). Символы CR и LF не включаются в возвращаемую строку. Фактически шаблон игнорирует все символы CR.

Если аргумент не указан, предполагается шаблон '*l', то есть шаблон чтения строки.

Тайм-аут операции чтения задаётся директивой конфигурации lua_socket_read_timeout и методом settimeout. При этом приоритет имеет последний. Например:

sock:settimeout(1000)  -- one second timeout
local line, err, partial = sock:receive()
if not line then
    ngx.say("failed to read a line: ", err)
    return
end
ngx.say("successfully read a line: ", line)

Здесь важно вызвать метод settimeout до вызова этого метода.

Начиная с выпуска v0.8.8 этот метод больше не закрывает автоматически текущее соединение при возникновении ошибки тайм-аута чтения. При других ошибках соединения этот метод всегда автоматически закрывает соединение.

Эта возможность впервые появилась в выпуске v0.5.0rc1.

tcpsock:receiveany

синтаксис: data, err = tcpsock:receiveany(max)

контекст: rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_client_hello_by_lua*

Возвращает любые данные, полученные подключённым сокетом, но не более max байт.

Этот метод является синхронной операцией, как и метод send, и на 100% не блокирует выполнение.

В случае успеха возвращает полученные данные; в случае ошибки возвращает nil со строкой, описывающей ошибку.

Если объём полученных данных превышает этот размер, метод вернёт ровно такое количество байт. Оставшиеся данные из базового буфера приёма могут быть возвращены при следующей операции чтения.

Тайм-аут операции чтения задаётся директивой конфигурации lua_socket_read_timeout и методом settimeouts. При этом приоритет имеет последний. Например:

sock:settimeouts(1000, 1000, 1000)  -- one second timeout for connect/read/write
local data, err = sock:receiveany(10 * 1024) -- read any data, at most 10K
if not data then
    ngx.say("failed to read any data: ", err)
    return
end
ngx.say("successfully read: ", data)

Этот метод не закрывает автоматически текущее соединение при возникновении ошибки тайм-аута чтения. При других ошибках соединения метод всегда автоматически закрывает соединение.

Эта возможность впервые появилась в выпуске v0.10.14.

tcpsock:receiveuntil

синтаксис: iterator = tcpsock:receiveuntil(pattern, options?)

контекст: rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_client_hello_by_lua*

Этот метод возвращает функцию-итератор Lua, которую можно вызывать для чтения потока данных до обнаружения указанного шаблона или возникновения ошибки.

Вот пример использования этого метода для чтения потока данных с последовательностью-разделителем --abcedhb:

local reader = sock:receiveuntil("\r\n--abcedhb")
local data, err, partial = reader()
if not data then
    ngx.say("failed to read the data stream: ", err)
end
ngx.say("read the data stream: ", data)

При вызове без аргументов функция-итератор возвращает полученные данные непосредственно перед указанной строкой-шаблоном во входящем потоке данных. Поэтому в приведённом выше примере, если входящий поток данных имеет вид 'hello, world! -agentzh\r\n--abcedhb blah blah', будет возвращена строка 'hello, world! -agentzh'.

В случае ошибки функция-итератор вернёт nil вместе со строкой, описывающей ошибку, и байтами частичных данных, прочитанными к этому моменту.

Функцию-итератор можно вызывать несколько раз, безопасно чередуя вызовы с другими методами cosocket или другими функциями-итераторами.

Функция-итератор ведёт себя иначе (то есть как настоящий итератор), если вызвать её с аргументом size. Это означает, что при каждом вызове она будет считывать size данных и при последнем вызове вернёт nil (при обнаружении шаблона-разделителя или возникновении ошибки). При последнем успешном вызове функции-итератора возвращаемое значение err также будет nil. После последнего успешного вызова, возвращающего данные nil и ошибку nil, функция-итератор будет сброшена. Рассмотрим следующий пример:

local reader = sock:receiveuntil("\r\n--abcedhb")

while true do
    local data, err, partial = reader(4)
    if not data then
        if err then
            ngx.say("failed to read the data stream: ", err)
            break
        end

        ngx.say("read done")
        break
    end
    ngx.say("read chunk: [", data, "]")
end

Тогда для входящего потока данных 'hello, world! -agentzh\r\n--abcedhb blah blah' приведённый выше пример выдаст следующий результат:

read chunk: [hell]
read chunk: [o, w]
read chunk: [orld]
read chunk: [! -a]
read chunk: [gent]
read chunk: [zh]
read done

Обратите внимание: фактически возвращаемые данные могут немного превышать ограничение размера, заданное аргументом size, если шаблон-разделитель неоднозначен при потоковом разборе. Вблизи конца потока данных возвращаемая строка также может быть короче ограничения размера.

Тайм-аут операции чтения функции-итератора задаётся директивой конфигурации lua_socket_read_timeout и методом settimeout. При этом приоритет имеет последний. Например:

local readline = sock:receiveuntil("\r\n")

sock:settimeout(1000)  -- one second timeout
line, err, partial = readline()
if not line then
    ngx.say("failed to read a line: ", err)
    return
end
ngx.say("successfully read a line: ", line)

Здесь важно вызвать метод settimeout до вызова функции-итератора (обратите внимание, вызов receiveuntil здесь не имеет значения).

Начиная с выпуска v0.5.1 этот метод также принимает необязательный аргумент-таблицу options для управления поведением. Поддерживаются следующие параметры:

  • inclusive

Параметр inclusive принимает логическое значение, определяющее, включать ли строку-шаблон в возвращаемую строку данных. По умолчанию используется значение false. Например:

local reader = tcpsock:receiveuntil("_END_", { inclusive = true })
local data = reader()
ngx.say(data)

Тогда для входящего потока данных "hello world _END_ blah blah blah" приведённый выше пример выведет hello world _END_, включая саму строку-шаблон _END_.

Начиная с выпуска v0.8.8 этот метод больше не закрывает автоматически текущее соединение при возникновении ошибки тайм-аута чтения. При других ошибках соединения этот метод всегда автоматически закрывает соединение.

Этот метод впервые появился в выпуске v0.5.0rc1.

tcpsock:close

синтаксис: ok, err = tcpsock:close()

контекст: rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_client_hello_by_lua*

Закрывает текущее TCP-соединение или сокет домена Unix типа stream. В случае успеха возвращает 1, в противном случае возвращает nil со строкой, описывающей ошибку.

Обратите внимание: вызывать этот метод для объектов сокетов, у которых был вызван метод setkeepalive, не нужно, поскольку объект сокета уже закрыт (а текущее соединение сохранено во встроенном пуле соединений).

Объекты сокетов, для которых этот метод не был вызван (и соответствующие соединения), будут закрыты, когда объект сокета будет освобождён сборщиком мусора Lua (Garbage Collector) или завершится обработка текущего клиентского HTTP-запроса.

Эта возможность впервые появилась в выпуске v0.5.0rc1.

tcpsock:settimeout

синтаксис: tcpsock:settimeout(time)

контекст: rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_client_hello_by_lua*

Задаёт значение тайм-аута в миллисекундах для последующих операций с сокетом (connect, receive и итераторов, возвращаемых методом receiveuntil).

Настройки, заданные этим методом, имеют приоритет над настройками, указанными в директивах конфигурации (то есть lua_socket_connect_timeout, lua_socket_send_timeout и lua_socket_read_timeout).

Обратите внимание: этот метод не влияет на настройку lua_socket_keepalive_timeout; для этой цели следует использовать аргумент timeout метода setkeepalive.

Эта возможность впервые появилась в выпуске v0.5.0rc1.

tcpsock:settimeouts

синтаксис: tcpsock:settimeouts(connect_timeout, send_timeout, read_timeout)

контекст: rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_client_hello_by_lua*

Задаёт соответственно пороговые значения тайм-аута для подключения, отправки и чтения (в миллисекундах) для последующих операций с сокетом (connect, send, receive и итераторов, возвращаемых методом receiveuntil).

Настройки, заданные этим методом, имеют приоритет над настройками, указанными в директивах конфигурации (то есть lua_socket_connect_timeout, lua_socket_send_timeout и lua_socket_read_timeout).

Рекомендуется использовать settimeouts вместо settimeout.

Обратите внимание: этот метод не влияет на настройку lua_socket_keepalive_timeout; для этой цели следует использовать аргумент timeout метода setkeepalive.

Эта возможность впервые появилась в выпуске v0.10.7.

tcpsock:setoption

синтаксис: ok, err = tcpsock:setoption(option, value?)

контекст: rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_client_hello_by_lua*

Эта функция добавлена для совместимости с API LuaSocket; её функциональность реализована v0.10.18.

Эта возможность впервые появилась в выпуске v0.5.0rc1.

В случае успеха функция возвращает true. В противном случае она возвращает nil и строку, описывающую ошибку.

Аргумент option — это строка с названием параметра, а значение зависит от устанавливаемого параметра:

  • keepalive

    Если задать для этого параметра значение true, для сокетов с установлением соединения будут отправляться сообщения keep-alive. Убедитесь, что функция connect была вызвана заранее, например:

    local ok, err = tcpsock:setoption("keepalive", true)
    if not ok then
        ngx.say("setoption keepalive failed: ", err)
    end
  • reuseaddr

    Включение этого параметра означает, что правила проверки адресов, указанных при вызове bind, должны разрешать повторное использование локальных адресов. Убедитесь, что функция connect была вызвана заранее, например:

    local ok, err = tcpsock:setoption("reuseaddr", 0)
    if not ok then
        ngx.say("setoption reuseaddr failed: ", err)
    end
  • tcp-nodelay

    Если задать для этого параметра значение true, алгоритм Нейгла для соединения будет отключён. Убедитесь, что функция connect была вызвана заранее, например:

    local ok, err = tcpsock:setoption("tcp-nodelay", true)
    if not ok then
        ngx.say("setoption tcp-nodelay failed: ", err)
    end
  • sndbuf

    Задаёт максимальный размер буфера отправки сокета в байтах. При установке с помощью setsockopt() ядро удваивает это значение (чтобы учесть дополнительные расходы на служебные данные). Убедитесь, что функция connect была вызвана заранее, например:

    local ok, err = tcpsock:setoption("sndbuf", 1024 * 10)
    if not ok then
        ngx.say("setoption sndbuf failed: ", err)
    end
  • rcvbuf

    Задаёт максимальный размер буфера приёма сокета в байтах. При установке с помощью setsockopt ядро удваивает это значение (чтобы учесть дополнительные расходы на служебные данные). Убедитесь, что функция connect была вызвана заранее, например:

    local ok, err = tcpsock:setoption("rcvbuf", 1024 * 10)
    if not ok then
        ngx.say("setoption rcvbuf failed: ", err)
    end

ПРИМЕЧАНИЕ: после установки параметр действует до закрытия соединения. Если вы знаете, что соединение получено из пула соединений и для всех соединений в пуле уже был вызван метод setoption() с требуемым значением параметра сокета, повторно вызывать setoption() можно не нужно, чтобы избежать накладных расходов от повторных вызовов. Например:

local count, err = tcpsock:getreusedtimes()
if not count then
    ngx.say("getreusedtimes failed: ", err)
    return
end

if count == 0 then
    local ok, err = tcpsock:setoption("rcvbuf", 1024 * 10)
    if not ok then
        ngx.say("setoption rcvbuf failed: ", err)
        return
    end
end

Описанные выше параметры поддерживаются в v0.10.18; в будущем будут реализованы и другие параметры.

tcpsock:setkeepalive

синтаксис: ok, err = tcpsock:setkeepalive(timeout?, size?)

контекст: rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_client_hello_by_lua*

Немедленно помещает соединение текущего сокета во встроенный пул соединений cosocket и сохраняет его активным, пока его не запросят другие вызовы метода connect или не истечёт соответствующий максимальный тайм-аут простоя.

Первый необязательный аргумент, timeout, позволяет задать максимальный тайм-аут простоя (в миллисекундах) для текущего соединения. Если аргумент не указан, используется значение по умолчанию из директивы конфигурации lua_socket_keepalive_timeout. Если задано значение 0, интервал тайм-аута не ограничен.

Второй необязательный аргумент size считается устаревшим начиная с выпуска v0.10.14 этого модуля; вместо него рекомендуется параметр pool_size метода connect. Начиная с выпуска v0.10.14 этот параметр действует только в том случае, если вызов connect ещё не создал пул соединений. Если параметр применяется (то есть вызов connect ранее не создал пул соединений), он задаёт размер пула и создаёт его. Если параметр не указан (и пул ещё не создан), используется размер по умолчанию, заданный директивой lua_socket_pool_size. В пуле соединений может храниться до size активных соединений, готовых к повторному использованию при последующих вызовах connect. Однако общее количество открытых соединений вне пула ничем не ограничено. Если количество соединений в пуле превысит его предельный размер, для освобождения места под текущее соединение будет закрыто наименее недавно использовавшееся соединение, уже находящееся в пуле. Обратите внимание: пул соединений cosocket существует для каждого рабочего процесса Nginx, а не для экземпляра сервера Nginx, поэтому указанный здесь предел размера действует для каждого отдельного рабочего процесса Nginx. Кроме того, после создания пула изменить его размер нельзя. Если нужно ограничить общее количество открытых соединений, укажите оба параметра — pool_size и backlog — при вызове connect.

В случае успеха этот метод возвращает 1; в противном случае он возвращает nil и строку, описывающую ошибку.

Если в системном буфере приёма текущего соединения остались непрочитанные данные, этот метод вернёт сообщение об ошибке «connection in dubious state» (в качестве второго возвращаемого значения), поскольку от предыдущего сеанса остались непрочитанные данные, которые будут доступны следующему сеансу, и повторно использовать соединение небезопасно.

Этот метод также переводит текущий объект cosocket в состояние «закрыт», поэтому после этого вручную вызывать для него метод close не нужно.

Эта возможность впервые появилась в выпуске v0.5.0rc1.

tcpsock:getreusedtimes

синтаксис: count, err = tcpsock:getreusedtimes()

контекст: rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_client_hello_by_lua*

Этот метод возвращает количество успешных повторных использований текущего соединения. В случае ошибки он возвращает nil и строку, описывающую ошибку.

Если текущее соединение получено не из встроенного пула соединений, этот метод всегда возвращает 0, то есть соединение ещё ни разу не использовалось повторно. Если соединение получено из пула, возвращаемое значение всегда отлично от нуля. Таким образом, этот метод также можно использовать, чтобы определить, получено ли текущее соединение из пула.

Эта возможность впервые появилась в выпуске v0.5.0rc1.

ngx.socket.connect

синтаксис: tcpsock, err = ngx.socket.connect(host, port)

синтаксис: tcpsock, err = ngx.socket.connect("unix:/path/to/unix-domain.socket")

контекст: rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*

Эта функция позволяет одним вызовом объединить ngx.socket.tcp() и вызов метода connect(). Фактически она реализована следующим образом:

local sock = ngx.socket.tcp()
local ok, err = sock:connect(...)
if not ok then
    return nil, err
end
return sock

Для этого метода нельзя использовать метод settimeout, чтобы задать тайм-аут подключения; вместо этого директиву lua_socket_connect_timeout необходимо задать во время настройки.

Эта возможность впервые появилась в выпуске v0.5.0rc1.

ngx.get_phase

синтаксис: str = ngx.get_phase()

контекст: init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, exit_worker_by_lua*, ssl_client_hello_by_lua*

Возвращает название текущей фазы выполнения. Возможные возвращаемые значения:

  • init для контекста init_by_lua*.
  • init_worker для контекста init_worker_by_lua*.
  • ssl_cert для контекста ssl_certificate_by_lua*.
  • ssl_session_fetch для контекста ssl_session_fetch_by_lua*.
  • ssl_session_store для контекста ssl_session_store_by_lua*.
  • ssl_client_hello для контекста ssl_client_hello_by_lua*.
  • set для контекста set_by_lua*.
  • rewrite для контекста rewrite_by_lua*.
  • balancer для контекста balancer_by_lua*.
  • access для контекста access_by_lua*.
  • content для контекста content_by_lua*.
  • header_filter для контекста header_filter_by_lua*.
  • body_filter для контекста body_filter_by_lua*.
  • log для контекста log_by_lua*.
  • timer для контекста пользовательских функций обратного вызова ngx.timer.*.
  • exit_worker для контекста exit_worker_by_lua*.

Этот API впервые появился в выпуске v0.5.10.

ngx.thread.spawn

синтаксис: co = ngx.thread.spawn(func, arg1, arg2, ...)

контекст: rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_client_hello_by_lua*

Создаёт новый пользовательский «лёгкий поток» с функцией Lua func и необязательными аргументами arg1, arg2 и т. д. Возвращает объект потока Lua (или сопрограммы Lua), представляющий этот «лёгкий поток».

«Лёгкие потоки» — это особый вид сопрограмм Lua, планированием которых управляет модуль ngx_lua.

До возврата из ngx.thread.spawn функция func будет вызываться с указанными необязательными аргументами, пока она не завершится, не прервётся из-за ошибки или не приостановится вследствие операций ввода-вывода через Nginx API for Lua (например, tcpsock:receive).

После возврата из ngx.thread.spawn вновь созданный «лёгкий поток» продолжит выполняться асинхронно, обычно при наступлении различных событий ввода-вывода.

Все фрагменты кода Lua, выполняемые директивами rewrite_by_lua, access_by_lua и content_by_lua, выполняются в стандартном «лёгком потоке», автоматически создаваемом ngx_lua. Такие стандартные «лёгкие потоки» также называются «входными потоками».

По умолчанию соответствующий обработчик Nginx (например, обработчик rewrite_by_lua) не завершится, пока не произойдёт одно из следующих событий:

  1. завершатся и «входной поток», и все пользовательские «лёгкие потоки»;
  2. «лёгкий поток» (входной или пользовательский) прервётся вызовом ngx.exit, ngx.exec, ngx.redirect или ngx.req.set_uri(uri, true); или
  3. «входной поток» завершится с ошибкой Lua.

Однако если пользовательский «лёгкий поток» завершается с ошибкой Lua, он не прерывает другие выполняющиеся «лёгкие потоки», как это делает «входной поток».

Из-за ограничений модели подзапросов Nginx, как правило, нельзя прервать выполняющийся подзапрос Nginx. Поэтому также запрещено прерывать выполняющийся «лёгкий поток», ожидающий один или несколько подзапросов Nginx. Перед выходом из «мира» необходимо вызвать ngx.thread.wait и дождаться завершения этих «лёгких потоков». Важное исключение: ожидающие подзапросы можно прервать, вызвав ngx.exit только с одним из следующих кодов состояния: ngx.ERROR (-1), 408, 444 или 499.

Планирование «лёгких потоков» не является вытесняющим. Иными словами, автоматическое разделение времени выполнения не производится. «Лёгкий поток» продолжает единолично использовать процессор, пока не произойдёт одно из следующих событий:

  1. операция ввода-вывода (без блокировки) не может быть завершена за один проход;
  2. поток вызывает coroutine.yield, чтобы добровольно уступить выполнение; или
  3. поток прерывается из-за ошибки Lua или вызова ngx.exit, ngx.exec, ngx.redirect либо ngx.req.set_uri(uri, true).

В первых двух случаях планировщик ngx_lua обычно возобновляет выполнение «лёгкого потока» позднее, если не происходит событие «остановки мира».

Пользовательские «лёгкие потоки» могут сами создавать «лёгкие потоки». Обычные пользовательские сопрограммы, созданные с помощью coroutine.create, также могут создавать «лёгкие потоки». Сопрограмма (обычная сопрограмма Lua или «лёгкий поток»), которая непосредственно создаёт «лёгкий поток», называется его «родительской сопрограммой».

«Родительская сопрограмма» может вызвать ngx.thread.wait, чтобы дождаться завершения дочернего «лёгкого потока».

Для сопрограмм «лёгких потоков» можно вызывать coroutine.status() и coroutine.yield().

Сопрограмма «лёгкого потока» может иметь статус «zombie», если:

  1. текущий «лёгкий поток» уже завершился (успешно или с ошибкой);
  2. его родительская сопрограмма всё ещё выполняется; и
  3. родительская сопрограмма не ожидает его с помощью ngx.thread.wait.

В следующем примере показано использование coroutine.yield() в сопрограммах «лёгких потоков» для ручного разделения времени выполнения:

local yield = coroutine.yield

function f()
    local self = coroutine.running()
    ngx.say("f 1")
    yield(self)
    ngx.say("f 2")
    yield(self)
    ngx.say("f 3")
end

local self = coroutine.running()
ngx.say("0")
yield(self)

ngx.say("1")
ngx.thread.spawn(f)

ngx.say("2")
yield(self)

ngx.say("3")
yield(self)

ngx.say("4")

В результате будет выведено:

0
1
f 1
2
f 2
3
f 3
4

«Лёгкие потоки» в основном полезны для выполнения параллельных запросов к вышестоящим серверам в рамках одного обработчика запроса Nginx. Это обобщённый вариант ngx.location.capture_multi, который работает со всем Nginx API for Lua. В следующем примере показаны параллельные запросы к MySQL, Memcached и вышестоящим HTTP-службам в одном обработчике Lua с выводом результатов в порядке их фактического получения (аналогично модели BigPipe компании Facebook):

-- query mysql, memcached, and a remote http service at the same time,
-- output the results in the order that they
-- actually return the results.

local mysql = require "resty.mysql"
local memcached = require "resty.memcached"

local function query_mysql()
    local db = mysql:new()
    db:connect{
                host = "127.0.0.1",
                port = 3306,
                database = "test",
                user = "monty",
                password = "mypass"
              }
    local res, err, errno, sqlstate =
            db:query("select * from cats order by id asc")
    db:set_keepalive(0, 100)
    ngx.say("mysql done: ", cjson.encode(res))
end

local function query_memcached()
    local memc = memcached:new()
    memc:connect("127.0.0.1", 11211)
    local res, err = memc:get("some_key")
    ngx.say("memcached done: ", res)
end

local function query_http()
    local res = ngx.location.capture("/my-http-proxy")
    ngx.say("http done: ", res.body)
end

ngx.thread.spawn(query_mysql)      -- create thread 1
ngx.thread.spawn(query_memcached)  -- create thread 2
ngx.thread.spawn(query_http)       -- create thread 3

Этот API впервые стал доступен в выпуске v0.7.0.

ngx.thread.wait

синтаксис: ok, res1, res2, ... = ngx.thread.wait(thread1, thread2, ...)

контекст: rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_client_hello_by_lua*

Ожидает завершения одного или нескольких дочерних «лёгких потоков» и возвращает результаты первого завершившегося «лёгкого потока» (успешно или с ошибкой).

Аргументы thread1, thread2 и т. д. — это объекты потоков Lua, возвращённые предыдущими вызовами ngx.thread.spawn.

Возвращаемые значения имеют то же значение, что и у coroutine.resume: первое возвращаемое значение — логическое значение, показывающее, завершился ли «лёгкий поток» успешно; последующие значения — возвращаемые значения пользовательской функции Lua, использованной для создания «лёгкого потока» (в случае успеха), либо объект ошибки (в случае неудачи).

Ожидать завершения дочернего «лёгкого потока» может только его непосредственная «родительская сопрограмма»; в противном случае будет вызвано исключение Lua.

В следующем примере показано использование ngx.thread.wait и ngx.location.capture для имитации ngx.location.capture_multi:

local capture = ngx.location.capture
local spawn = ngx.thread.spawn
local wait = ngx.thread.wait
local say = ngx.say

local function fetch(uri)
    return capture(uri)
end

local threads = {
    spawn(fetch, "/foo"),
    spawn(fetch, "/bar"),
    spawn(fetch, "/baz")
}

for i = 1, #threads do
    local ok, res = wait(threads[i])
    if not ok then
        say(i, ": failed to run: ", res)
    else
        say(i, ": status: ", res.status)
        say(i, ": body: ", res.body)
    end
end

По сути, здесь реализована модель «дождаться всех».

Ниже приведён пример модели «дождаться любого»:

function f()
    ngx.sleep(0.2)
    ngx.say("f: hello")
    return "f done"
end

function g()
    ngx.sleep(0.1)
    ngx.say("g: hello")
    return "g done"
end

local tf, err = ngx.thread.spawn(f)
if not tf then
    ngx.say("failed to spawn thread f: ", err)
    return
end

ngx.say("f thread created: ", coroutine.status(tf))

local tg, err = ngx.thread.spawn(g)
if not tg then
    ngx.say("failed to spawn thread g: ", err)
    return
end

ngx.say("g thread created: ", coroutine.status(tg))

ok, res = ngx.thread.wait(tf, tg)
if not ok then
    ngx.say("failed to wait: ", res)
    return
end

ngx.say("res: ", res)

-- stop the "world", aborting other running threads
ngx.exit(ngx.OK)

В результате будет выведен следующий текст:

f thread created: running
g thread created: running
g: hello
res: g done

Этот API впервые стал доступен в выпуске v0.7.0.

ngx.thread.kill

синтаксис: ok, err = ngx.thread.kill(thread)

контекст: rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_client_hello_by_lua*

Завершает работающий «лёгкий поток», созданный с помощью ngx.thread.spawn. В случае успеха возвращает значение true, в противном случае — nil и строку с описанием ошибки.

Согласно текущей реализации, завершить поток может только родительская корутина (или «лёгкий поток»). Кроме того, работающий «лёгкий поток» с ожидающими подзапросами Nginx (например, инициированными с помощью ngx.location.capture) нельзя завершить из-за ограничения ядра Nginx.

Этот API впервые стал доступен в выпуске v0.9.9.

ngx.on_abort

синтаксис: ok, err = ngx.on_abort(callback)

контекст: rewrite_by_lua*, access_by_lua*, content_by_lua*

Регистрирует пользовательскую функцию Lua в качестве обратного вызова, который автоматически вызывается, когда клиент преждевременно закрывает соединение (в направлении downstream).

Если обратный вызов успешно зарегистрирован, возвращает 1, в противном случае — nil и строку с описанием ошибки.

В функции обратного вызова можно использовать весь API Nginx для Lua, поскольку функция выполняется в специальном «лёгком потоке», подобно «лёгким потокам», созданным с помощью ngx.thread.spawn.

Функция обратного вызова может самостоятельно решать, что делать при прерывании соединения клиентом. Например, она может просто проигнорировать это событие, ничего не делая, и текущий обработчик запроса Lua продолжит выполнение без прерываний. Функция обратного вызова также может решить завершить всё, вызвав, например, ngx.exit,

local function my_cleanup()
    -- custom cleanup work goes here, like cancelling a pending DB transaction

    -- now abort all the "light threads" running in the current request handler
    ngx.exit(499)
end

local ok, err = ngx.on_abort(my_cleanup)
if not ok then
    ngx.log(ngx.ERR, "failed to register the on_abort callback: ", err)
    ngx.exit(500)
end

Если для lua_check_client_abort задано значение off (по умолчанию), этот вызов функции всегда будет возвращать сообщение об ошибке "lua_check_client_abort is off".

Согласно текущей реализации, эту функцию можно вызвать только один раз в рамках одного обработчика запроса; последующие вызовы вернут сообщение об ошибке "duplicate call".

Этот API впервые появился в выпуске v0.7.4.

См. также lua_check_client_abort.

ngx.timer.at

синтаксис: hdl, err = ngx.timer.at(delay, callback, user_arg1, user_arg2, ...)

контекст: init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, ssl_client_hello_by_lua*

Создаёт таймер Nginx с пользовательской функцией обратного вызова и необязательными пользовательскими аргументами.

Первый аргумент, delay, задаёт задержку таймера в секундах. Здесь можно указать дробное значение, например 0.001, что означает 1 миллисекунду. Также можно задать задержку 0 — в этом случае таймер немедленно сработает, когда текущий обработчик уступит выполнение.

Второй аргумент, callback, может быть любой функцией Lua, которая будет вызвана позднее в фоновом «лёгком потоке» после указанной задержки. Ядро Nginx автоматически вызовет пользовательскую функцию обратного вызова с аргументами premature, user_arg1, user_arg2 и т. д. Аргумент premature принимает логическое значение, указывающее, является ли срабатывание таймера преждевременным (для таймера с задержкой 0 он всегда равен false), а user_arg1, user_arg2 и т. д. — это дополнительные пользовательские аргументы, указанные при вызове ngx.timer.at в качестве оставшихся аргументов.

Преждевременное срабатывание таймера происходит, когда рабочий процесс Nginx пытается завершить работу, например при перезагрузке конфигурации Nginx, инициированной сигналом HUP, или при завершении работы сервера Nginx. Когда рабочий процесс Nginx пытается завершить работу, создать новые таймеры с ненулевой задержкой с помощью ngx.timer.at уже нельзя; в этом случае ngx.timer.at вернёт «условное ложное» значение и строку с описанием ошибки, то есть "process exiting".

Начиная с выпуска v0.9.3, таймеры с нулевой задержкой можно создавать даже после того, как рабочий процесс Nginx начал завершать работу.

После срабатывания таймера пользовательский код Lua в функции обратного вызова таймера выполняется в «лёгком потоке», полностью отделённом от исходного запроса, создавшего таймер. Поэтому объекты с тем же временем жизни, что и у создавшего их запроса, например cosockets, нельзя использовать совместно в исходном запросе и пользовательской функции обратного вызова таймера.

Простой пример:

location / {
    ...
    log_by_lua_block {
        local function push_data(premature, uri, args, status)
            -- push the data uri, args, and status to the remote
            -- via ngx.socket.tcp or ngx.socket.udp
            -- (one may want to buffer the data in Lua a bit to
            -- save I/O operations)
        end
        local ok, err = ngx.timer.at(0, push_data,
                                     ngx.var.uri, ngx.var.args, ngx.header.status)
        if not ok then
            ngx.log(ngx.ERR, "failed to create timer: ", err)
            return
        end

        -- other job in log_by_lua_block
    }
}

Можно также создавать бесконечные повторяющиеся таймеры, например таймер, срабатывающий каждые 5 секунд, рекурсивно вызывая ngx.timer.at в функции обратного вызова таймера. Вот такой пример:

local delay = 5
local handler
handler = function (premature)
    -- do some routine job in Lua just like a cron job
    if premature then
        return
    end
    local ok, err = ngx.timer.at(delay, handler)
    if not ok then
        ngx.log(ngx.ERR, "failed to create the timer: ", err)
        return
    end

    -- do something in timer
end

local ok, err = ngx.timer.at(delay, handler)
if not ok then
    ngx.log(ngx.ERR, "failed to create the timer: ", err)
    return
end

-- do other jobs

Однако для создания повторяющихся таймеров рекомендуется использовать функцию API ngx.timer.every, поскольку она надёжнее.

Поскольку функции обратного вызова таймеров выполняются в фоновом режиме и их время работы не увеличивает время ответа на запрос клиента, таймеры могут быстро накапливаться на сервере и исчерпывать системные ресурсы из-за ошибок в программах на Lua или просто из-за слишком большого количества клиентского трафика. Чтобы предотвратить серьёзные последствия, например сбой сервера Nginx, существуют встроенные ограничения на количество «ожидающих таймеров» и «работающих таймеров» в рабочем процессе Nginx. Под «ожидающими таймерами» здесь понимаются таймеры, которые ещё не сработали, а «работающие таймеры» — это таймеры, чьи пользовательские функции обратного вызова выполняются в данный момент.

Максимальное количество ожидающих таймеров в рабочем процессе Nginx задаётся директивой lua_max_pending_timers. Максимальное количество работающих таймеров задаётся директивой lua_max_running_timers.

Согласно текущей реализации, каждый «работающий таймер» занимает одну (фиктивную) запись подключения из глобального списка записей подключений, настроенного стандартной директивой worker_connections в nginx.conf. Поэтому убедитесь, что директива worker_connections задана достаточно большим значением, учитывающим как реальные подключения, так и фиктивные подключения, необходимые для функций обратного вызова таймеров (с учётом ограничения, заданного директивой lua_max_running_timers).

В контексте функций обратного вызова таймеров доступно множество API Lua для Nginx: потоковые/датаграммные cosocket-подключения (ngx.socket.tcp и ngx.socket.udp), словари общей памяти (ngx.shared.DICT), пользовательские корутины (coroutine.*), пользовательские «лёгкие потоки» (ngx.thread.*), ngx.exit, ngx.now/ngx.time, ngx.md5/ngx.sha1_bin. Однако API подзапросов (например, ngx.location.capture), API ngx.req.* и API вывода в downstream (например, ngx.say, ngx.print и ngx.flush) в этом контексте явно отключены.

Обратите внимание: каждый таймер основан на фиктивном запросе (который, в свою очередь, основан на фиктивном подключении). Поскольку Nginx освобождает память при закрытии подключения, вызов большого количества API, выделяющих память, например tcpsock:connect, внутри таймера приведёт к накоплению ресурсов памяти. Поэтому после нескольких таких вызовов рекомендуется создать новый таймер, чтобы освободить ресурсы памяти.

В функцию обратного вызова таймера можно передавать большинство стандартных значений Lua (nil, логические значения, числа, строки, таблицы, замыкания, файловые дескрипторы и т. д.) — явно в качестве пользовательских аргументов или неявно в качестве upvalue замыкания обратного вызова. Однако есть несколько исключений: нельзя передавать объекты потоков, возвращённые функциями coroutine.create и ngx.thread.spawn, а также объекты cosocket, возвращённые функциями ngx.socket.tcp, ngx.socket.udp и ngx.req.socket, поскольку время жизни этих объектов привязано к контексту создавшего их запроса, тогда как функция обратного вызова таймера отделена от контекста создавшего её запроса (по замыслу) и выполняется в собственном (фиктивном) контексте запроса. Если попытаться использовать объекты потоков или cosocket за пределами создавшего их запроса, возникнет ошибка "no co ctx found" (для потоков) или "bad request" (для cosocket). При этом все эти объекты можно создавать непосредственно внутри функции обратного вызова таймера.

Обратите внимание, что обработчик Lua таймера имеет собственную копию специальной таблицы ngx.ctx. Она не использует ту же ngx.ctx, что и обработчик Lua, создавший таймер. Если нужно передать данные от создателя таймера обработчику таймера, используйте дополнительные параметры ngx.timer.at().

Этот API впервые появился в выпуске v0.8.0.

ngx.timer.every

синтаксис: hdl, err = ngx.timer.every(delay, callback, user_arg1, user_arg2, ...)

контекст: init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, ssl_client_hello_by_lua*

Похожа на функцию API ngx.timer.at, но

  1. delay не может быть равна нулю,
  2. таймер будет создаваться каждые delay секунд, пока текущий рабочий процесс Nginx не начнёт завершать работу.

Как и в случае с ngx.timer.at, аргумент callback будет автоматически вызван с аргументами premature, user_arg1, user_arg2 и т. д.

В случае успеха возвращает «условное истинное» значение (но не true). В противном случае возвращает «условное ложное» значение и строку с описанием ошибки.

Этот API также учитывает директивы lua_max_pending_timers и lua_max_running_timers.

Этот API впервые появился в выпуске v0.10.9.

ngx.timer.running_count

синтаксис: count = ngx.timer.running_count()

контекст: init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, exit_worker_by_lua*, ssl_client_hello_by_lua*

Возвращает количество работающих в данный момент таймеров.

Эта директива впервые появилась в выпуске v0.9.20.

ngx.timer.pending_count

синтаксис: count = ngx.timer.pending_count()

контекст: init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, exit_worker_by_lua*, ssl_client_hello_by_lua*

Возвращает количество ожидающих таймеров.

Эта директива впервые появилась в выпуске v0.9.20.

ngx.config.subsystem

синтаксис: subsystem = ngx.config.subsystem

контекст: set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, init_by_lua*, init_worker_by_lua*, exit_worker_by_lua*

Это строковое поле указывает подсистему Nginx, на которой основана текущая среда Lua. Для этого модуля значение поля всегда равно строке "http". Однако для ngx_stream_lua_module значение этого поля равно "stream".

Это поле впервые появилось в 0.10.1.

ngx.config.debug

синтаксис: debug = ngx.config.debug

контекст: set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, init_by_lua*, init_worker_by_lua*, exit_worker_by_lua*

Это логическое поле указывает, является ли текущая сборка Nginx отладочной, то есть была ли она собрана с параметром ./configure --with-debug.

Это поле впервые появилось в 0.8.7.

ngx.config.prefix

синтаксис: prefix = ngx.config.prefix()

контекст: set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, init_by_lua*, init_worker_by_lua*, exit_worker_by_lua*

Возвращает путь к «префиксу» сервера Nginx, определённый параметром командной строки -p при запуске исполняемого файла Nginx, либо путь, заданный параметром командной строки --prefix при сборке Nginx с помощью скрипта ./configure.

Эта функция впервые появилась в 0.9.2.

ngx.config.nginx_version

синтаксис: ver = ngx.config.nginx_version

контекст: set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, init_by_lua*, init_worker_by_lua*, exit_worker_by_lua*

Это поле содержит целое число, обозначающее номер версии используемого ядра Nginx. Например, номер версии 1.4.3 преобразуется в число Lua 1004003.

Этот API впервые появился в выпуске 0.9.3.

ngx.config.nginx_configure

синтаксис: str = ngx.config.nginx_configure()

контекст: set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, init_by_lua*

Эта функция возвращает строку с аргументами команды Nginx ./configure.

Этот API впервые появился в выпуске 0.9.5.

ngx.config.ngx_lua_version

синтаксис: ver = ngx.config.ngx_lua_version

контекст: set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, init_by_lua*

Это поле содержит целое число, обозначающее номер версии используемого модуля ngx_lua. Например, номер версии 0.9.3 преобразуется в число Lua 9003.

Этот API впервые появился в выпуске 0.9.3.

ngx.worker.exiting

синтаксис: exiting = ngx.worker.exiting()

контекст: set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, init_by_lua*, init_worker_by_lua*, exit_worker_by_lua*

Эта функция возвращает логическое значение, указывающее, начал ли текущий рабочий процесс Nginx завершение работы. Рабочий процесс Nginx завершает работу при остановке сервера Nginx или перезагрузке конфигурации (также называемой перезагрузкой HUP).

Этот API впервые появился в выпуске 0.9.3.

ngx.worker.pid

синтаксис: pid = ngx.worker.pid()

контекст: set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, init_by_lua*, init_worker_by_lua*, exit_worker_by_lua*

Эта функция возвращает число Lua, соответствующее идентификатору процесса (PID) текущего рабочего процесса Nginx. Этот API эффективнее, чем ngx.var.pid, и может использоваться в контекстах, где нельзя применять API ngx.var.VARIABLE (например, в init_worker_by_lua).

Этот API впервые появился в выпуске 0.9.5.

ngx.worker.pids

синтаксис: pids = ngx.worker.pids()

контекст: set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, exit_worker_by_lua*

Эта функция возвращает таблицу Lua с идентификаторами процессов (PID) всех рабочих процессов Nginx. При запуске или перезапуске рабочего процесса Nginx использует канал для передачи PID текущего рабочего процесса другому рабочему процессу. Поэтому с помощью этого API можно получить PID всех текущих рабочих процессов. В Windows этот API недоступен.

Этот API впервые появился в выпуске 0.10.23.

ngx.worker.count

синтаксис: count = ngx.worker.count()

контекст: set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, init_by_lua*, init_worker_by_lua*, exit_worker_by_lua*

Возвращает общее количество рабочих процессов Nginx (то есть значение, заданное директивой worker_processes в nginx.conf).

Этот API впервые появился в выпуске 0.9.20.

ngx.worker.id

синтаксис: id = ngx.worker.id()

контекст: set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, init_worker_by_lua*, exit_worker_by_lua*

Возвращает порядковый номер текущего рабочего процесса Nginx (нумерация начинается с 0).

Таким образом, если общее количество рабочих процессов равно N, этот метод может вернуть число от 0 до N - 1 включительно.

Эта функция возвращает осмысленные значения только в Nginx версии 1.9.1 и выше. В более ранних версиях Nginx она всегда возвращает nil.

См. также ngx.worker.count.

Этот API впервые появился в выпуске 0.9.20.

ngx.semaphore

синтаксис: local semaphore = require "ngx.semaphore"

Это модуль Lua, реализующий классический API семафоров для эффективной синхронизации разных «лёгких потоков». Поддерживается также совместное использование одного семафора разными «лёгкими потоками», созданными в разных контекстах (запросах), если эти «лёгкие потоки» находятся в одном рабочем процессе Nginx, а директива lua_code_cache включена (что является значением по умолчанию).

Этот модуль Lua не входит в состав самого модуля ngx_lua, а поставляется вместе с библиотекой lua-resty-core.

Дополнительные сведения см. в документации к этому модулю Lua ngx.semaphore в составе lua-resty-core.

Для этой функции требуется ngx_lua версии не ниже v0.10.0.

ngx.balancer

синтаксис: local balancer = require "ngx.balancer"

Этот модуль Lua предоставляет API Lua для создания полностью динамических балансировщиков нагрузки на чистом Lua.

Этот модуль Lua не входит в состав самого модуля ngx_lua, а поставляется вместе с библиотекой lua-resty-core.

Дополнительные сведения см. в документации к этому модулю Lua ngx.balancer в составе lua-resty-core.

Для этой функции требуется ngx_lua версии не ниже v0.10.0.

ngx.ssl

синтаксис: local ssl = require "ngx.ssl"

Этот модуль Lua предоставляет функции API для управления процессом SSL-рукопожатия в таких контекстах, как ssl_certificate_by_lua*.

Этот модуль Lua не входит в состав самого модуля ngx_lua, а поставляется вместе с библиотекой lua-resty-core.

Дополнительные сведения см. в документации к этому модулю Lua ngx.ssl.

Для этой функции требуется ngx_lua версии не ниже v0.10.0.

ngx.ocsp

синтаксис: local ocsp = require "ngx.ocsp"

Этот модуль Lua предоставляет API для выполнения запросов OCSP, проверки ответов OCSP и настройки OCSP stapling.

Обычно этот модуль используется вместе с модулем ngx.ssl в контексте ssl_certificate_by_lua*.

Этот модуль Lua не входит в состав самого модуля ngx_lua, а поставляется вместе с библиотекой lua-resty-core.

Дополнительные сведения см. в документации к этому модулю Lua ngx.ocsp.

Для этой функции требуется ngx_lua версии не ниже v0.10.0.

ndk.set_var.DIRECTIVE

синтаксис: res = ndk.set_var.DIRECTIVE_NAME

контекст: init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, exit_worker_by_lua*, ssl_client_hello_by_lua*

Этот механизм позволяет вызывать директивы других модулей Nginx на C, реализованные с помощью ndk_set_var_value подмодуля set_var из Nginx Devel Kit (NDK).

Например, таким способом можно вызывать следующие директивы set-misc-nginx-module:

  • set_quote_sql_str
  • set_quote_pgsql_str
  • set_quote_json_str
  • set_unescape_uri
  • set_escape_uri
  • set_encode_base32
  • set_decode_base32
  • set_encode_base64
  • set_decode_base64
  • set_encode_hex
  • set_decode_hex
  • set_sha1
  • set_md5

Например:

local res = ndk.set_var.set_escape_uri('a/b')
-- now res == 'a%2fb'

Аналогичным образом из Lua можно вызывать следующие директивы, предоставляемые encrypted-session-nginx-module:

  • set_encrypt_session
  • set_decrypt_session

Для этой функции требуется модуль ngx_devel_kit.

coroutine.create

синтаксис: co = coroutine.create(f)

контекст: rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, ssl_client_hello_by_lua*

Создаёт пользовательскую корутину Lua с помощью функции Lua и возвращает объект корутины.

Аналогично стандартному API Lua coroutine.create, но работает в контексте корутин Lua, созданных ngx_lua.

Этот API впервые стал доступен в контексте init_by_lua* начиная с 0.9.2.

Этот API впервые появился в выпуске v0.6.0.

coroutine.resume

синтаксис: ok, ... = coroutine.resume(co, ...)

контекст: rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, ssl_client_hello_by_lua*

Возобновляет выполнение ранее приостановленной или только что созданной пользовательской корутины Lua.

Подобно стандартному API Lua coroutine.resume, но работает в контексте сопрограмм Lua, созданных ngx_lua.

Этот API впервые стал доступен в контексте init_by_lua* начиная с 0.9.2.

Этот API впервые появился в выпуске v0.6.0.

coroutine.yield

синтаксис: ... = coroutine.yield(...)

контекст: rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, ssl_client_hello_by_lua*

Приостанавливает выполнение текущей пользовательской сопрограммы Lua.

Подобно стандартному API Lua coroutine.yield, но работает в контексте сопрограмм Lua, созданных ngx_lua.

Этот API впервые стал доступен в контексте init_by_lua* начиная с 0.9.2.

Этот API впервые появился в выпуске v0.6.0.

coroutine.wrap

синтаксис: co = coroutine.wrap(f)

контекст: rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, ssl_client_hello_by_lua*

Подобно стандартному API Lua coroutine.wrap, но работает в контексте сопрограмм Lua, созданных ngx_lua.

Этот API впервые стал доступен в контексте init_by_lua* начиная с 0.9.2.

Этот API впервые появился в выпуске v0.6.0.

coroutine.running

синтаксис: co = coroutine.running()

контекст: rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, ssl_client_hello_by_lua*

Идентичен стандартному API Lua coroutine.running.

Этот API впервые стал доступен в контексте init_by_lua* начиная с 0.9.2.

Этот API впервые стал доступен в выпуске v0.6.0.

coroutine.status

синтаксис: status = coroutine.status(co)

контекст: rewrite_by_lua*, access_by_lua*, content_by_lua*, init_by_lua*, ngx.timer.*, header_filter_by_lua*, body_filter_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, ssl_client_hello_by_lua*

Идентичен стандартному API Lua coroutine.status.

Этот API впервые стал доступен в контексте init_by_lua* начиная с 0.9.2.

Этот API впервые стал доступен в выпуске v0.6.0.

ngx.run_worker_thread

синтаксис: ok, res1, res2, ... = ngx.run_worker_thread(threadpool, module_name, func_name, arg1, arg2, ...)

контекст: rewrite_by_lua*, access_by_lua*, content_by_lua*

Этот API всё ещё является экспериментальным и может быть изменён в будущем без предварительного уведомления.

Этот API доступен только в Linux.

Обёртка для рабочего потока nginx, предназначенная для выполнения функции Lua. Вызывающая сопрограмма будет приостановлена до завершения функции.

В функции function_name модуля module можно использовать только следующие API ngx_lua:

  • ngx.encode_base64

  • ngx.decode_base64

  • ngx.hmac_sha1

  • ngx.encode_args

  • ngx.decode_args

  • ngx.quote_sql_str

  • ngx.crc32_short

  • ngx.crc32_long

  • ngx.hmac_sha1

  • ngx.md5_bin

  • ngx.md5

  • ngx.config.subsystem

  • ngx.config.debug

  • ngx.config.prefix

  • ngx.config.nginx_version

  • ngx.config.nginx_configure

  • ngx.config.ngx_lua_version

  • ngx.shared.DICT

Первый аргумент threadpool задаёт имя пула потоков Nginx, определённого с помощью thread_pool.

Второй аргумент module_name задаёт имя модуля Lua для выполнения в рабочем потоке; модуль должен возвращать таблицу Lua. Модуль должен находиться в пути поиска пакетов, например:

lua_package_path '/opt/openresty/?.lua;;';

Третий аргумент func_name задаёт поле функции в таблице модуля, указанной вторым аргументом.

Тип args должен быть одним из следующих:

  • boolean
  • number
  • string
  • nil
  • table (таблица может быть рекурсивной и содержать элементы указанных выше типов.)

ok имеет логический тип и указывает на ошибку на уровне C (не удалось получить поток из пула потоков, не удалось выполнить pcall функции модуля и т. д.). Если ok равно false, res1 содержит строку ошибки.

Возвращаемые значения (res1, ...) возвращаются при вызове функции модуля. Обычно res1 должно иметь логический тип, чтобы вызывающий код мог проверить наличие ошибки.

Этот API полезен, если необходимо выполнить задачи следующих типов:

  • Задачи с высокой нагрузкой на ЦП, например вычисление md5
  • Задачи ввода-вывода файлов
  • Вызов os.execute() или блокирующего API C через ffi
  • Вызов внешней библиотеки Lua, не основанной на cosocket или nginx

Пример 1: вычисление md5.

location /calc_md5 {
    default_type 'text/plain';

    content_by_lua_block {
        local ok, md5_or_err = ngx.run_worker_thread("testpool", "md5", "md5")
        ngx.say(ok, " : ", md5_or_err)
    }
}

md5.lua

local function md5()
    return ngx.md5("hello")
end

return { md5=md5, }

Пример 2: запись журналов в файл журнала.

location /write_log_file {
    default_type 'text/plain';

    content_by_lua_block {
        local ok, err = ngx.run_worker_thread("testpool", "write_log_file", "log", ngx.var.arg_str)
        if not ok then
            ngx.say(ok, " : ", err)
            return
        end
        ngx.say(ok)
    }
}

write_log_file.lua

local function log(str)
    local file, err = io.open("/tmp/tmp.log", "a")
    if not file then
        return false, err
    end
    file:write(str)
    file:flush()
    file:close()
    return true
end
return {log=log}

Устаревшие разделы

В этом разделе собрана устаревшая документация, разделы которой были переименованы или удалены, чтобы существующие ссылки в интернете продолжали работать.

Специальные последовательности PCRE

Этот раздел переименован в Специальные последовательности экранирования.

Поддержка байт-кода Lua/LuaJIT

Этот раздел переименован в Поддержка байт-кода LuaJIT. Начиная с версии v0.10.16 этого модуля стандартный интерпретатор Lua (также известный как «PUC-Rio Lua») больше не поддерживается.

© 2009–2017 Xiaozhe Wang (chaoslawful)
© 2009–2019 Yichun "agentzh" Zhang (章亦春), OpenResty Inc.
Licensed under the BSD License.
https://github.com/openresty/lua-nginx-module/blob/v0.10.28/README.markdown

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API