Динамическое принятие блоковых запросов в Apache mod_cgi (и ответ)

Вопрос или проблема

Я работаю с приложением mod_cgi и клиентом, который отправляет данные в виде чанков в течение определенного времени. Но проблема в том, что на сервере мой CGI-скрипт не может ответить, пока клиент не завершит соединение.

Я могу использовать Wireshark вместе с curl для отправки чанковых запросов и проверки, что отправляю их правильно:

for i in $(seq 5); do date; sleep 1; done | \
 curl --noproxy '*' -H "Transfer-Encoding: chunked" \
     -H "Content-Type: application/json" -X POST -T - \
     https://example.com/test.cgi

Я вижу, что запрос начинается, и чанковые сообщения начинают передаваться.

Но на сервере, запущенном на Apache 2.4.57, я использую mod_cgi со следующими флагами:

    Options +ExecCGI
    AddHandler cgi-script .cgi

Приложение вызывается, но ответить невозможно, пока запрос не завершен.

Как я могу заставить Apache вызывать CGI-скрипт после установки соединения, когда запрос сделан, но данные неполные?

Я нашел ссылку здесь с кем-то, кто сказал, что это возможно, но нигде больше в интернете не сказано, как это сделать: https://stackoverflow.com/a/284869/2926815

Редактирование: я также нашел эту ссылку с тем, кто указал, как сделать это на стороне клиента с помощью curl https://unix.stackexchange.com/a/469060/510722 (это и есть то, как я получил свои аргументы для тестирования) – и я действительно подтвердил, что curl на самом деле отправляет чанковые данные в нужное время.

Ответ или решение

Для решения вашей задачи по обработке запросов в формате chunked с помощью Apache и mod_cgi, необходимо учесть, что стандартная конфигурация mod_cgi не поддерживает немедленное выполнение CGI-скриптов и их ответы до завершения всей передачи данных. Однако вы можете рассмотреть несколько альтернативных подходов для достижения желаемого поведения.

1. Использование mod_proxy и mod_wsgi

Одним из возможных решений является использование mod_proxy и mod_wsgi для обработки частично завершенных запросов. Это позволит вам создать proxied-сервер, который будет динамически обрабатывать входящие данные и отвечать на них по мере их получения.

Пример настройки:

  1. Установка необходимых модулей:
    Убедитесь, что mod_proxy и mod_wsgi установлены и активированы в вашей системе.

  2. Настройка Apache:
    В вашем файле конфигурации Apache добавьте следующие строки:

    LoadModule proxy_module modules/mod_proxy.so
    LoadModule proxy_http_module modules/mod_proxy_http.so
    LoadModule wsgi_module modules/mod_wsgi-py3.x.x.so
    
    <VirtualHost *:80>
       ServerName example.com
    
       WSGIScriptAlias /test /path/to/your/script.wsgi
    
       <Directory /path/to/your>
           Require all granted
       </Directory>
    
       # Опция для обработки chunked запросов
       ProxyRequests Off
       ProxyPass /test http://localhost:8000/test
       ProxyPassReverse /test http://localhost:8000/test
    </VirtualHost>
  3. Создание WSGI-приложения:
    Пример простого WSGI-приложения, которое может обрабатывать входящие chunked запросы:

    def application(environ, start_response):
       status = '200 OK'
       headers = [('Content-type', 'text/plain')]
       start_response(status, headers)
    
       # Чтение данных по мере их поступления
       try:
           request_body_size = int(environ.get('CONTENT_LENGTH', 0))
           request_body = environ['wsgi.input'].read(request_body_size)
           yield f"Received data: {request_body}\n"
       except Exception as e:
           yield f"Error: {str(e)}\n"

2. Использование mod_event и mod_fastcgi

Если вы не хотите использовать Python, вы можете рассмотреть возможность использования mod_fastcgi или mod_fcgid, которые могут обеспечить лучшую обработку асинхронных запросов.

Пример настройки:

  1. Убедитесь, что mod_fcgid установлен и активирован.

  2. Настройте сервер для поддержки FastCGI, добавив следующие строки:

    LoadModule fcgid_module modules/mod_fcgid.so
    
    <IfModule mod_fcgid.c>
       AddHandler fcgid-script .cgi
       Options +ExecCGI
    </IfModule>
  3. Используйте FastCGI скрипт для обработки входящих подключений, который будет отвечать сразу же после получения данных.

Заключение

Подводя итог, mod_cgi не будет оптимальным выбором для вашего сценария, так как он требует завершения запроса перед отправкой ответа. Вместо этого рекомендуется использовать mod_wsgi или mod_fcgid, которые могут обрабатывать асинхронные запросы и предоставлять данные клиенту по мере их поступления. Эти изменения позволят вашему приложению быстрее внедрять ответ и обрабатывать данные, поступающие от клиента.

Оцените материал
Добавить комментарий

Капча загружается...