Pull to refresh

Comments 23

Код выполняется асинхронно, не вмешиваясь в основной цикл событий Nginx

Это значит, что новый поток создается на каждый запрос?
Как понимаю, автотесты для такого кода не напишешь? Только отдельными утилитами, поднимая nginx в докере и кидая в него запросы.
Это значит, что новый поток создается на каждый запрос?

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

Кажется это вы что-то напутали. Предлагаю наводящий вопрос: что произойдёт, если в lua-коде окажется вечный цикл?

То поток заблокируется. Какой именно поток — зависит от реализации, скорей-всего из отдельного пула. Само по себе суждение "используются асинхронные вызовы" не даёт информации о том, в каком потоке это будет происходить. И уж тем более из этого не следует, что на каждый запрос будет создаваться поток. Асинхронно можно делать и в одном потоке (см. javascript).

Мой наводящий вопрос был именно к тому, какой именно поток заблокируется.
UFO just landed and posted this here
Кэширование с Upstream

Ничего не кеширует, просто будет держать соединения к апстриму за счет Keep-Alive.


serve_image.lua

мне кажется, проще будет это сделать на proxy_pass + proxy_cache*.


Но за статью спасибо, было интересно.


PS: На убунте, если не нужен весь openresty, а именно lua, достаточно ничего не компилируя поставить сам nginx (или нет, если у вас уже установлен) и доставить к нему модули. например, так:
apt-get install nginx
apt-get install nginx-extras

UFO just landed and posted this here
UFO just landed and posted this here

Зачем так сложно-то? Размещаем статику просто на поддомене без кукисов и всё.

UFO just landed and posted this here
Если задача сэкономить трафик и облегчить жизнь проксям, то резать куки в nginx уже поздновато, разве нет?
UFO just landed and posted this here

Кусок из рабочего конфига:


header_filter_by_lua_block {
    local NewCookies = ngx.header['Set-Cookie'] -- get cookies
    <cut>
    ngx.header['Set-Cookie'] = NewCookies
}

Для очистки, вероятно, будет достаточно присвоить пустой table или nil.

хочу чтобы в конце было всё для докера чтобы быстро запустить этот Hello World и не копипастить кучу команд
Сделал для себя docker и добавил помимо всего прочего в него еще автогенерацию ssl от letsencrypt, сжатие контента плагином brotli, опциональное подключение модуля pagespeed от гугла и набор параметров, полезных для повышения безопасности сервера
https://github.com/fjedi/awesome-nginx-in-docker
Бонус! Примеры без использования Lua вообще

Какие-то каличные примеры. Приведу своих. Они может и не идеальны, но работают исправно без лишней нагрузки на мозг.
1) Раздача файлов через nginx с проверкой на доступ к загрузке, авторизация или еще что (auth_request)
nginx
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 "";
    }
}


php
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)
nginx
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;
    }
}


php
// /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);
    });

а что мелочитесь с функциями «безопасности»?
$filename = parse_url(stripslashes(htmlentities(strip_tags(nl2br(quoted_printable_encode(htmlspecialchars(basename($_SERVER['REQUEST_URI']))))))), PHP_URL_PATH);
Реинкарнация mod_perl?
Дурацкий вопрос — а зачем? Как только народ начнет накручивать логику на подобные сценарии, он наступит ровно на те же грабли, что возникали с mod_perl. Разве нет?
Лично я пользуюсь lua-resty-auto-ssl. Вполне удобный кейс.
Хорошая штука. У нас уже используется.
В связке с ngx_postgres — вообще бомба получается.
Отличная статья, спасибо. Обучаясь в одном иностранном колледже, писал простой учебный проект на OpenResty, REST сервис, работающий через Nginx+Lua с MySQL. Простейшие тесты показали огромную производительность на слабеньком учебном ПК.
На текущей работе используем связку OpenResty+PowerDNS в качестве распределённого по геозонам DNS кластера.
Sign up to leave a comment.