Вопрос или проблема
Я работаю с приложением 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-сервер, который будет динамически обрабатывать входящие данные и отвечать на них по мере их получения.
Пример настройки:
-
Установка необходимых модулей:
Убедитесь, чтоmod_proxy
иmod_wsgi
установлены и активированы в вашей системе. -
Настройка 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>
-
Создание 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
, которые могут обеспечить лучшую обработку асинхронных запросов.
Пример настройки:
-
Убедитесь, что
mod_fcgid
установлен и активирован. -
Настройте сервер для поддержки FastCGI, добавив следующие строки:
LoadModule fcgid_module modules/mod_fcgid.so <IfModule mod_fcgid.c> AddHandler fcgid-script .cgi Options +ExecCGI </IfModule>
-
Используйте FastCGI скрипт для обработки входящих подключений, который будет отвечать сразу же после получения данных.
Заключение
Подводя итог, mod_cgi
не будет оптимальным выбором для вашего сценария, так как он требует завершения запроса перед отправкой ответа. Вместо этого рекомендуется использовать mod_wsgi
или mod_fcgid
, которые могут обрабатывать асинхронные запросы и предоставлять данные клиенту по мере их поступления. Эти изменения позволят вашему приложению быстрее внедрять ответ и обрабатывать данные, поступающие от клиента.