Комментарии 23
Код выполняется асинхронно, не вмешиваясь в основной цикл событий Nginx
Это значит, что новый поток создается на каждый запрос?
Как понимаю, автотесты для такого кода не напишешь? Только отдельными утилитами, поднимая nginx в докере и кидая в него запросы.
Это значит, что новый поток создается на каждый запрос?
Это значит, что используются асинхронные вызовы. Прекратите уже путать асинхронность и параллельность. Это не связанные между собой понятия, и возможны все четыре варианта их комбинации.
То поток заблокируется. Какой именно поток — зависит от реализации, скорей-всего из отдельного пула. Само по себе суждение "используются асинхронные вызовы" не даёт информации о том, в каком потоке это будет происходить. И уж тем более из этого не следует, что на каждый запрос будет создаваться поток. Асинхронно можно делать и в одном потоке (см. javascript).
Кэширование с Upstream
Ничего не кеширует, просто будет держать соединения к апстриму за счет Keep-Alive.
serve_image.lua
мне кажется, проще будет это сделать на proxy_pass + proxy_cache*.
Но за статью спасибо, было интересно.
PS: На убунте, если не нужен весь openresty, а именно lua, достаточно ничего не компилируя поставить сам nginx (или нет, если у вас уже установлен) и доставить к нему модули. например, так:
apt-get install nginx
apt-get install nginx-extras
Зачем так сложно-то? Размещаем статику просто на поддомене без кукисов и всё.
Кусок из рабочего конфига:
header_filter_by_lua_block {
local NewCookies = ngx.header['Set-Cookie'] -- get cookies
<cut>
ngx.header['Set-Cookie'] = NewCookies
}
Для очистки, вероятно, будет достаточно присвоить пустой table или nil.
https://github.com/fjedi/awesome-nginx-in-docker
Бонус! Примеры без использования Lua вообще
Какие-то каличные примеры. Приведу своих. Они может и не идеальны, но работают исправно без лишней нагрузки на мозг.
1) Раздача файлов через nginx с проверкой на доступ к загрузке, авторизация или еще что (auth_request)
server {
root /var/www/example.com;
location ~ \.(zip|png)$ {
auth_request /auth;
add_header Cache-Control no-cache;
}
location = /auth {
internal;
proxy_pass https://example.com/check_auth;
proxy_set_header X-Original-URI $request_uri;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
}
}
function user_check_auth()
{
if (is_granted())
{
header('HTTP/1.1 200 OK');
header('Status: 200 OK');
} else {
header('HTTP/1.1 403 Forbidden');
header('Status: 403 Forbidden');
}
exit;
}
2) Подсчет кол-ва загрузок (X-Accel-Redirect)
server{
root /var/www/example.com;
set $counter /var/www/files/src/counter.php;
location ~ ^/files/(?<g1>.*\.zip)$ {
fastcgi_pass unix:/usr/local/var/run/php-fpm.sock;
fastcgi_param SCRIPT_FILENAME $counter;
include fastcgi_params;
fastcgi_param DOCUMENT_ROOT $realpath_root;
fastcgi_param REQUEST_URI /$g1;
fastcgi_param X-File-Type arch_zip;
set $_uri /$g1;
}
location @counter {
root /var/www/upload.example.com;
try_files $_uri =404;
}
location / {
try_files $uri $uri/ =404;
}
}
// /var/www/files/src/counter.php
<?php
header('X-Accel-Redirect: @counter');
header('Content-Type: application/octet-stream');
use Symfony\Component\Console\Input\ArrayInput;
if (!empty($_SERVER['REQUEST_URI']) && !empty($_SERVER['X-File-Type'])) {
$filename = parse_url(htmlspecialchars(basename($_SERVER['REQUEST_URI'])), PHP_URL_PATH);
$fileType = htmlspecialchars($_SERVER['X-File-Type']);
require_once __DIR__ . '/../vendor/autoload.php';
set_time_limit(10);
$input = new ArrayInput([
'counter:tick',
'filename' => $filename,
'type' => $fileType,
]);
$app = require __DIR__ . '/app.php';
require __DIR__ . '/../config/prod.php';
/* @var \Symfony\Component\Console\Application $console */
$console = require __DIR__ . '/console.php';
try {
$console->run($input);
} catch (\Exception $exception) {
return;
}
}
// /var/www/files/src/console.php
<?php
// ...
$console->register('counter:tick')
->setDescription('Counter for download files')
->setDefinition([
new InputArgument('filename', InputArgument::REQUIRED, 'File name'),
new InputArgument('type', InputArgument::REQUIRED, 'File Type')
])
->setCode(function (InputInterface $input) use ($app) {
$filename = $input->getArgument('filename');
$fileType = $input->getArgument('type');
/* @var \Uploader\Entity\FileType $type */
$type = $app['repository.file_type']->findByType($fileType);
if (!$type) {
return;
}
/* @var \Uploader\Entity\File $file */
$file = $app['repository.file']->findByTypeAndName($type->getType(), $filename);
if (!$file) {
return;
}
$file->incDownloadCount();
$app['repository.file']->save($file);
});
Дурацкий вопрос — а зачем? Как только народ начнет накручивать логику на подобные сценарии, он наступит ровно на те же грабли, что возникали с mod_perl. Разве нет?
В связке с ngx_postgres — вообще бомба получается.
На текущей работе используем связку OpenResty+PowerDNS в качестве распределённого по геозонам DNS кластера.
Программируем прямо в Nginx