При разработке на Common Lisp проблема отдачи статических файлов стоит значительнее менее остро, ибо язык сам по себе намного быстрее и Hunchentoot справляется с этой работой достаточно быстро. Я для публикации статических файлов пользуюсь restas-directory-publisher - модулем для RESTAS. Однако, следует признать, что возможны ситуации, когда отдавать статику средствами CL окажется не очень разумно.
Тут вот и возникла идея обеспечить возможность использования механизма XSendfile прозрачным для основной логики образом. В итоге, я добавил в RESTAS соответствующие декораторы для Apache и Nginx.
Ниже я приведу возможные примеры использования этих декораторов в пакете restas-doc, обеспечивающего работу http://restas.lisper.ru/.
для публикации файлов я использую такой код:
(restas:mount-submodule -publisher- (#:restas.directory-publisher))При этом, сами файлы с документацией лежат в каталоге /usr/share/doc/restas/.
@apache-xsendfile
При работе с Apache всё просто:
(restas:mount-submodule -publisher- (#:restas.directory-publisher restas:@apache-xsendfile))а в конфиге Apache необходимо установить значение параметра XSendFilePath таким образом, что бы публикуемые файлы оказались внутри указанного каталога. Самый простой путь
XSendFilePath /Но это может оказаться не очень разумным с точки зрения администрирования, так что в данном случае можно и так
XSendFilePath /usr/share/doc/restas/Более подробная информация о настройке сервера есть в официальной документации.
@nginx-accel-redirect
Настройка nginx является более сложной. Необходимо создать internal-секцию и дальше есть два варианта: либо установить root, либо задать alias. В зависимости от выбранного варианта необходимо различным образом формировать заголовок X-Accel-Redirect. Для поддержки этих вариантов в RESTAS добавлено три переменных:
(defvar *nginx-internal-location* nil)и их надо настроить точно в соответствии с настройками nginx. При этом, переменные *nginx-internal-alias* и *nginx-internal-root* являются взаимоисключающими и одна из них должна быть установлена в NIL. В принципе, их можно выставить глобально, но RESTAS позволяет сделать лучше. Например, для такого конфига nginx:
(defvar *nginx-internal-alias* nil)
(defvar *nginx-internal-root* nil)
Код на CL может быть таким:
location /restas {
internal;
root /usr/share/doc;
}
(restas:mount-submodule -publisher- (#:restas.directory-publisher restas:@nginx-accel-redirect)Настройка с root представляется мне довольно неудобной и если nginx поднят только для CL, то гораздо проще делать так
(restas:*nginx-internal-location* #P"/restas/")
(restas:*nginx-internal-root* #P"/usr/share/doc/"))
location /protected/ {и
internal;
alias /usr/share/doc/restas/;
}
(restas:mount-submodule -publisher- (#:restas.directory-publisher restas:@nginx-accel-redirect)Вообще, описанный функционал обеспечивает очень важную возможность работать со статическими файлами средствами CL, например, создавать повторно используемые компоненты, а в случае возникновения необходимости легко подключить механизм XSendFile с помощью подключения нужного декоратора.
(restas:*nginx-internal-location* "/protected/")
(restas:*nginx-internal-alias* "/usr/share/doc/restas/"))
Я пока разбирался с этими вопрос успел посмотреть советы по использованию XSendFile с RoR и Django - там это носит вид хаков, жёстко прибивающих код к конкретной конфигурации веб-сервера. Этот факт подкрепил моё мнение, что модель декораторов RESTAS вкупе с возможностями CL (такими, как CLOS) обеспечивает более гибкие и мощные возможности, чем более традиционная схема с middleware-компонентами.
Любопытно. Только вот не понял, как получается, что хттп-запрос принимает лисп, а отдаёт Апач? Тот же пхп сам поверх апача сидит, а лисп отдельно, как он перехватывает инициативу?
ОтветитьУдалить@Demetrius Cond
ОтветитьУдалитьА это на самом деле абсолютно всё равно, сидит ли что-то внутри, подключается через ProxyPass или ещё как. Ведь это внутренний фильтр, который обрабатывает заголовки и когда встречает X-Sendfile вместо передачи контента начинает обрабатывать указанный файл.
@Demetrius Conde
ОтветитьУдалитьХм, или я не правильно понял вопрос? В общем, я использую ProxyPass.
Что-то я не понял, какой смысл в подключении nginx/apache?
ОтветитьУдалитьВедь те же права доступа можно легко проверить средствами Лиспа. Да хоть тот же декоратор повесить.
??
@linkfly
ОтветитьУдалитьСмысл в скорости и масштабируемости. Как раз всякие права и т.п. я хочу в лиспе обрабатывать. А саму техническую часть отдачи файла клиенту на nginx возложить. Вообще, размещение Hunchentoot за nginx может существенно повысить производительность системы. Если же говорить только об отдаче статики, то например в Hunchentoot только сейчас добавили поддержку Range, да и то, полного соответствия спецификации нет. А Nginx делает это и многое другое хорошо.
Интересно, что есть Range и где об этом можно почитать?
ОтветитьУдалитьА что за "техническая часть отдачи файла клиенту"? Что может быть такого у nginx, кроме грамотного кэширования статики?
@linkfly
ОтветитьУдалитьRange - это например возможность докачки файлов.
nginx использует epoll и написан на C