ngx_http_lua_module
Название
ngx_http_lua_module — встраивание возможностей Lua в HTTP-серверы Nginx.
Этот модуль — основной компонент OpenResty. Если вы используете этот модуль, значит, по сути, вы используете OpenResty :)
Этот модуль не распространяется вместе с исходным кодом Nginx. См. инструкции по установке.
Содержание
- Название
- Статус
- Версия
- Видео
- Краткий обзор
- Описание
- Типичные варианты использования
- Совместимость с Nginx
- Установка
- Сообщество
- Репозиторий кода
- Ошибки и исправления
- Поддержка байт-кода LuaJIT
- Поддержка системных переменных окружения
- Поддержка HTTP 1.0
- Статическая компоновка модулей на чистом Lua
- Совместное использование данных в рамках рабочего процесса Nginx
-
Известные проблемы
- Проблемы с подключением TCP-сокета
- Приостановка и возобновление корутин Lua
- Область видимости переменных Lua
- Локации, настроенные директивами подзапросов других модулей
- Cosocket доступны не везде
- Специальные последовательности экранирования
- Совместное использование с SSI не поддерживается
- Режим SPDY поддерживается не полностью
- Отсутствие данных в запросах, обработка которых прерывается досрочно
- Список задач
- Изменения
- Набор тестов
- Авторские права и лицензия
- См. также
- Директивы
- API Nginx для Lua
- Устаревшие разделы
Статус
Готов к эксплуатации в производственной среде.
Версия
В этом документе описан ngx_lua v0.10.25, выпущенный 19 июня 2023 года.
Видео
-
Видео на YouTube «Пример Hello World HTTP с OpenResty/Lua»
-
Видео на YouTube «Создание собственных модулей Lua для приложений OpenResty/Nginx»
-
Видео на YouTube «Демонстрация утилиты командной строки resty в OpenResty»
-
Видео на YouTube «Правильное измерение времени выполнения кода Lua в OpenResty»
-
Видео на YouTube «Предварительная компиляция модулей Lua в байт-код LuaJIT для ускорения запуска OpenResty»
Подписывайтесь на наш официальный канал 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:
- LuaJIT можно скачать из последнего выпуска ветки LuaJIT от OpenResty. Также поддерживаются официальные выпуски LuaJIT 2.x, хотя производительность будет значительно ниже по причинам, описанным выше.
- Скачайте последнюю версию модуля ngx_devel_kit (NDK) ЗДЕСЬ
- Скачайте последнюю версию ngx_lua ЗДЕСЬ
- Скачайте последнюю поддерживаемую версию Nginx ЗДЕСЬ (см. раздел «Совместимость с Nginx»).
- Скачайте последнюю версию lua-resty-core ЗДЕСЬ
- Скачайте последнюю версию 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.
Ошибки и исправления
Сообщения об ошибках, пожелания и исправления можно отправить следующим образом:
- создать обращение в трекере ошибок GitHub;
- или написать в сообщество OpenResty.
Поддержка байт-кода LuaJIT
Посмотрите видео на YouTube «Правильное измерение времени выполнения кода Lua в OpenResty»
Начиная с выпуска 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 (даже неявно), состояние гонки возникнуть не может. Поэтому всегда проявляйте особую осторожность при совместном использовании изменяемых данных на уровне рабочего процесса. Ошибочные оптимизации могут легко привести к состояниям гонки, которые трудно отлаживать под нагрузкой.
Если необходимо совместно использовать данные на уровне всего сервера, используйте один или несколько следующих подходов:
- Используйте API ngx.shared.DICT, предоставляемый этим модулем.
- Используйте только один рабочий процесс Nginx и один сервер (однако это не рекомендуется для компьютеров с многоядерным процессором или несколькими процессорами).
- Используйте механизмы хранения данных, такие как
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, поскольку:
- неправильное использование глобальных переменных Lua отрицательно сказывается на параллельных запросах, если такие переменные должны быть локальными;
- для доступа к глобальным переменным Lua требуется поиск в таблице глобального окружения, что требует значительных вычислительных затрат;
- в ссылках на некоторые глобальные переменные 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:
-
Приложения:
- 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_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 (что требует экранирования специальных символов) и имеет следующие особенности:
- Эта директива поддерживает дополнительные аргументы после скрипта 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 <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
- 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(...)
контекст: 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. Это зависит от следующих условий:
- превышает ли размер тела текущего запроса значение client_body_buffer_size,
- и включена ли директива 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 в следующих случаях:
- тело запроса не было прочитано;
- тело запроса было прочитано во временные файлы на диске;
- или размер тела запроса равен нулю.
Если тело запроса ещё не прочитано, сначала вызовите 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(по умолчанию) 303307308
По умолчанию используется 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.
синтаксис: 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.
синтаксис: 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.
синтаксис: 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.
синтаксис: 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.
синтаксис: 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.
синтаксис: 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.
синтаксис: 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.
синтаксис: 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(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.
синтаксис: 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 и сообщение об ошибке.
Если ключ не существует в общем словаре или срок его действия уже истёк:
- если аргумент
initне указан или имеет значениеnil, метод вернётnilи строку ошибки"not found"; либо - если аргумент
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.
синтаксис: 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.
синтаксис: 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.
синтаксис: 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.
синтаксис: 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.
синтаксис: 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.
синтаксис: 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.
синтаксис: 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()
контекст: 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.
синтаксис: 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.
синтаксис: 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.
синтаксис: 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.
синтаксис: 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»). Для этого объекта поддерживаются следующие методы:
Предполагается совместимость с 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) не завершится, пока не произойдёт одно из следующих событий:
- завершатся и «входной поток», и все пользовательские «лёгкие потоки»;
- «лёгкий поток» (входной или пользовательский) прервётся вызовом ngx.exit, ngx.exec, ngx.redirect или ngx.req.set_uri(uri, true); или
- «входной поток» завершится с ошибкой Lua.
Однако если пользовательский «лёгкий поток» завершается с ошибкой Lua, он не прерывает другие выполняющиеся «лёгкие потоки», как это делает «входной поток».
Из-за ограничений модели подзапросов Nginx, как правило, нельзя прервать выполняющийся подзапрос Nginx. Поэтому также запрещено прерывать выполняющийся «лёгкий поток», ожидающий один или несколько подзапросов Nginx. Перед выходом из «мира» необходимо вызвать ngx.thread.wait и дождаться завершения этих «лёгких потоков». Важное исключение: ожидающие подзапросы можно прервать, вызвав ngx.exit только с одним из следующих кодов состояния: ngx.ERROR (-1), 408, 444 или 499.
Планирование «лёгких потоков» не является вытесняющим. Иными словами, автоматическое разделение времени выполнения не производится. «Лёгкий поток» продолжает единолично использовать процессор, пока не произойдёт одно из следующих событий:
- операция ввода-вывода (без блокировки) не может быть завершена за один проход;
- поток вызывает coroutine.yield, чтобы добровольно уступить выполнение; или
- поток прерывается из-за ошибки 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», если:
- текущий «лёгкий поток» уже завершился (успешно или с ошибкой);
- его родительская сопрограмма всё ещё выполняется; и
- родительская сопрограмма не ожидает его с помощью 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, но
-
delayне может быть равна нулю, - таймер будет создаваться каждые
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:
Для этой функции требуется модуль 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




