Программирование на языке Ruby.
19.7. Ruby и Web-сервер.
На сегодняшний день одним из самых популярных Web-серверов является Apache. Если вы работаете с ним, то должны знать о модуле mod_ruby, который описывается в разделе 19.7.1.
Еще одна полезная возможность на стороне сервера — встроенный Ruby; эту технологию поддерживают инструменты erb (рассматриваемый ниже) и eruby. Они позволяют встраивать код на Ruby в текст страницы (обычно HTML или XML), вследствие чего данные можно вставлять динамически. Данный подход описывается в разделе 19.7.2.
Некоторые разработчики реализовали Web-серверы, написанные целиком на Ruby. Естественно возникает вопрос: зачем писать новый Web-сервер, когда их уже и так существует немало — взять хотя бы тот же Apache?
Во-первых, есть ситуации, когда желательно иметь специализированный Web-сервер, например ради нестандартного способа обработки страниц, когда можно пожертвовать функциональностью ради скорости, или для автоматической трансляции специальной разметки в HTML.
Во-вторых, может возникнуть желание поэкспериментировать с поведением сервера и его взаимодействием с внешним кодом, например с CGI-программами. Возможно, у вас есть какие-то идеи относительно создания сервера приложений и среды разработки на стороне сервера. А все мы знаем, что Ruby прекрасно подходит для экспериментов.
В-третьих, иногда бывает разумно встроить Web-сервер в другое приложение. К этой возможности прибегают разработчики, желающие предоставить функциональность программной системы внешнему миру; протокол HTTP прост и четко определен, а Web-браузеры в качестве клиентов есть повсюду. Этот прием можно даже использовать для удаленной отладки, если система часто обновляет свое внутреннее состояние и делает его доступным встроенному серверу.
И последняя причина заключается в том, что небольшой автономный Web-сервер может упростить развертывание и конфигурирование. Например, перезапустить сервер для приложения Rails гораздо проще, если в этом качестве выступает WEBrick, а не Apache.
Имея все это в виду, посмотрим, что Ruby предлагает в плане Web-серверов. В прошлом было по крайней мере четыре таких сервера, но летом 2006 года остались два наиболее значимых: WEBrick и Mongrel. Они описаны в разделах 19.7.3 и 19.7.4 соответственно.
19.7.1. Модуль mod_ruby.
Обычно, если CGI-сценарий пишется на интерпретируемом языке, то при каждом запросе загружается новый экземпляр интерпретатора. Это дорого обходится с точки зрения потребления ресурсов сервера и времени выполнения.
Сервер Apache решает эту проблему путем создания загружаемых модулей, которые, по существу, становятся частью сервера. Они загружаются динамически по мере необходимости и становятся общими для всех зависящих от них сценариев. Одним из таких модулей является mod_ruby (имеется в архиве RAA).
Модуль mod_ruby реализует несколько директив Apache, в частности:
• RubyRequire определяет одну или несколько потребных библиотек;
• RubyHandler определяет обработчик для объекта Ruby;
• RubyPassEnv определяет имена переменных окружения, передаваемых сценариям;
• RubySetEnv устанавливает переменные окружения;
• RubyTimeOut задает величину тайм-аута для Ruby-сценариев;
• RubySafeLevel задает уровень безопасности $SAFE;
• RubyKanjiCode устанавливает кодировку символов для Ruby.
В состав пакета входят также классы и модули Ruby для взаимодействия с Apache. Модуль Apache (здесь слово «модуль» употребляется в смысле, принятом в Ruby) включает несколько функций, например server_version и unescape_url; там же определены классы Request и Table.
Apache::Request — это обертка для типа данных request_rec, определяющая такие методы, как request_method, content_type, readlines и т.д. Класс Apache::Table — обертка для типа данных table; он определяет, среди прочих, методы get, add и each.
Имеются подробные инструкции по компиляции и установке пакета mod_ruby. Обратитесь к поставляемой в комплекте с ним документации (или эквивалентной информации в Сети).
19.7.2. Использование erb.
Для начала договоримся о терминологии. Речь не идет о встраивании интерпретатора Ruby в электронные устройства, скажем, в телевизор или тостер. Мы говорим о встраивании кода на Ruby в текст.
Далее отметим, что встраивать Ruby-код в текстовые файлы можно несколькими способами. В этом разделе мы рассмотрим лишь самый общеупотребительный инструмент, а именно программу erb (автор Шуго Маэда).
Почему мы упоминаем подобный инструмент в связи с Web? Очевидно, потому, что чаще всего Ruby-код встраивается в HTML или XML-тексты.
Но можно придумать и другие применения. Например, в старомодных текстовых играх, или в каких-нибудь утилитах слияния почты, или как часть задания cron для динамического создания файла с «сообщением дня» ( /etc/motd) в полночь. Не ограничивайте свое воображение. Ищите новые интересные применения erb и делитесь своими находками с сообществом. Большая часть примеров в этом разделе носит общий (и потому искусственный) характер, конкретно с HTML они почти не связаны.
Утилита erb — это просто фильтр или препроцессор. Для выделения кода, выражений и комментариев, написанных на Ruby, применяется специальная нотация, весь остальной текст передается без изменений.
Текст, который нужно специально обрабатывать, заключается в скобки <% и %>. Есть три вида такой нотации, отличающиеся первым символом внутри «тега».
Если первый символ — знак равенства ( =), то содержимое рассматривается как выражение Ruby; результат его вычисления подставляется в текущее место файла, например:
This is <%= "ylno".reverse %> a test.
Do <%= "NOT".downcase %> be alarmed.
Если назвать этот файл myfile.txt, то для его фильтрации надо будет выполнить команду:
Erb myfile.txt.
Результат направляется на стандартный вывод:
This is only a test.
Do not be alarmed.
Комментарий вводится символом #:
Life <%# so we've heard %> is but a dream.
Как и следовало ожидать, комментарии игнорируются, то есть мы увидим такой результат:
Life is but a dream.
Все остальные символы после знака процента рассматриваются как часть кода. Все, что этот код выводит (не результат вычисления значения), помещается в текстовый поток. Для удобства восприятия рекомендую оставлять после процента пробел, хотя erb этого и не требует.
В следующем примере тег в первой строчке ничего не вставляет в текст, так как ничего не выводит. Во вторую же строку вставляется 42, как и следовало ожидать.
Ответ равен <% "42" %>.
А точнее, ответ равен <% puts "42" %>.
Результат получается такой:
Ответ равен .
А точнее, ответ равен 42.
Фрагменты кода на Ruby не являются независимыми. Так, переменную, определенную в одном теге, можно использовать в следующем за ним.
<% x=3; y=4; z=5 %>
Если стороны треугольника равны <%=x%>, <%=y%> и <%=z%>,
Мы знаем, что он прямоугольный, поскольку.
<%= x*x %> + <%= y*y %> = <%= z*z %>.
Пробелы внутри тегов в последней строке необязательны, но с ними текст становится понятнее. Выводится следующий текст:
Если стороны треугольника равны 3, 4 и 5,
Мы знаем, что он прямоугольный, поскольку.
9 + 16 = 25.
Попробуйте сделать внутри тега синтаксическую ошибку. Вы обнаружите, что erb выдает очень подробное сообщение, в котором печатается сгенерированный код и максимально точно указывается место ошибки.
Что если включить «магическую строку» в сам текст в виде литерала? Экранирование с помощью обратной косой черты не работает. Мы рекомендуем такой способ:
В этой строке есть цепочка меньше-процент <%="<%"%>,
А в этой больше-процент <%="%"+">"%>.
Здесь мы видим <%="<%="%> и <%="<%#"%>.
Результат таков:
В этой строке есть цепочка меньше-процент <%,
А в этой больше-процент >%.
Здесь мы видим <% и <%#.
Включать открывающий тег немного проще, чем закрывающий. Объясняется это тем, что теги не могут быть вложенными, а программа erb недостаточно «умная», чтобы игнорировать закрывающий символ внутри строки.
Конечно, в erb есть кое-какие функции, «заточенные» под HTML. Для установки режима работы предназначен флаг -M, он может принимать значения f, с и n.
Режим f (фильтр) подразумевается по умолчанию, поэтому во всех предыдущих примерах мы не задавали флаг -Mf явно. В режиме -Mc (CGI) все ошибки печатаются в виде HTML. В режиме -Mn (NPH-CGI — без разбора заголовков) автоматически выводятся дополнительные HTTP-заголовки. В двух последних режимах для безопасности переменная $SAFE устанавливается в 1 (исходя из допущения, что это CGI-приложение, которое может вызвать враждебный пользователь). Флаг -n (и эквивалентный ему --noheader) подавляет вывод CGI-заголовка.
Можно настроить сервер Apache так, что он будет распознавать страницы с встроенным кодом на Ruby. Для этого нужно ассоциировать тип application/x-httpd-erb с каким-нибудь расширением (было бы логично использовать .rhtml) и определить действие, которое ассоциирует этот тип с исполняемым файлом eruby. Более подробные сведения вы найдете в документации по Apache.
19.7.3. Сервер WEBrick.
Авторами WEBrick являются Масаёси Такахаши (Masayoshi Takahashi) и Юзоу Готоу (Yuuzou Gotou) при участии многих других разработчиков. Это библиотека для создания полноценного HTTP-сервера; она входит в стандартный дистрибутив Ruby. Название происходит от слова «brick» (кирпич) — то есть подразумевается нечто небольшое, компактное и автономное.
WEBrick почти ничего не знает о деталях Web-приложений. Он не понимает, что такое сеанс пользователя и прочие тонкости. Он оперирует лишь сервлетами, работающими независимо друг от друга. Если вам необходима функциональность более высокого уровня, поищите другую библиотеку (возможно, надстройку над WEBrick наподобие IOWA или Tofu) или напишите свою собственную.
Работа с WEBrick сводится к такой последовательности действий: создается экземпляр сервера; определяются обработчики монтирования и обработчики сигналов; запускается сервер. Вот небольшой пример:
Require 'webrick'.
Server = WEBrick::HTTPServer.new(:DocumentRoot => '.').
# (В этом простом примере нет обработчиков монтирования).
Trap('INT') { server.shutdown}.
Trap('TERM') { server.shutdown}.
Server.start.
Запустив эту программу, вы получите Web-сервер, работающий на стандартном порте 80. Он раздает файлы из текущего каталога.
Для создания сервлета требуется создать класс, производный от WEBrick::HTTPServlet::AbstractServlet. При обработке указанного в запросе URL сервер ищет самый длинный префикс (наилучшее соответствие). Ниже приведен «пустой» пример (в нем обработчики не делают ничего полезного):
Class EventsHandler < HTTPServlet::AbstractServlet.
# ...
End.
Class RecentHandler < HTTPServlet::AbstractServlet.
# ...
End.
Class AlphaHandler < HTTPServlet::AbstractServlet.
# ...
End.
# ...
Server.mount('/events', EventsHandler).
Server.mount('/events/recent', RecentHandler).
Server.mount('/events/alpha', AlphaHandler).
Как работает сервлет? Идея в том, чтобы определить метод для каждой поддерживаемой HTTP-операции, например do_GET для запросов типа GET. Если вы привыкли писать программы, обращающиеся к серверу, то теперь придется встать на противоположную точку зрения, ведь ваш код становится частью Web-сервера. Вы не получаете ошибку с кодом 404, а сами посылаете этот код. Вот простой пример:
Class TinyHandler < WEBrick::HTTPServlet::AbstractServlet.
def do_GET(request, response).
# Обработать запрос, вернуть ответ.
status, ctype, body = process_request(request).
response.status = status.
response['Content-type'] = ctype.
response.body = body.
end.
def process_request(request).
text = "Очень короткая Web-страница...".
return 200, "text/html", text.
end.
End.
В более сложном сервлете, вероятно, использовался бы метод initialize. Тогда передаваемые ему параметры были бы последними при вызове метода server.mount.
К счастью, не нужно писать сервлеты для каждой крохотной задачки, которую должен выполнять WEBrick. У него есть несколько своих предопределенных сервлетов (все в пространстве имен WEBrick::HTTPServlet):
• FileHandler.
• ProcHandler.
• CGIHandler.
• ERBHandler.
Поскольку сервлет ProcHandler особенно интересен, скажем о нем несколько слов. Он позволяет «лениться», то есть не создавать подкласса AbstractServlet. Вместо этого мы передаем proc:
# Непосредственное монтирование блока...
Server.mount_proc('/here') do |req, resp|
resp.body = "Это то, что выводит мой блок.".
End.
# Создать объект Proc и смонтировать его...
Some_proc = Proc.new do |req, resp|
resp.body = ' Это то, что выводит мой Proc.'.
End.
Server.mount_proc('/there', some_proc).
# Другой способ смонтировать Proc...
My_handler = HTTPServlet::ProcHandler.new(some_proc)).
Server.mount('/another', my_handler).
WEBrick располагает и многими другими возможностями, например точками подключения для выполнения дополнительных задач (скажем, запуска какой-нибудь программы при старте). Имеются также развитые средства протоколирования, аутентификации по протоколу HTTP и т.д. Дополнительную информацию ищите в онлайновой документации на сайте http://ruby-doc.org или где-либо еще.
19.7.4. Сервер Mongrel.
Автором Mongrel является Зед Шоу (Zed Shaw) при участии других. Основная цель этого сервера — повысить производительность по сравнению с WEBrick. В данном отношении он добился значительных успехов и работает во много раз быстрее (хотя провести точные измерения сложно: результат зависит от многих факторов).
Mongrel часто используют в сочетании с Rails, а документация местами ориентирована на Rails. Но жесткой привязки к Rails нет — сервер может работать и в других контекстах.
Mongrel — скорее, приложение, тогда как WEBrick больше напоминает библиотеку. Во многом они схожи, но порядок запуска и API различаются.
Во многих случаях Mongrel можно запустить как приложение без написания какого-либо кода. Он понимает три основные команды: start, stop и restart. У команды start много параметров, модифицирующих поведение сервера, например: --port portnum, --log filename, --daemonize и т.д. Чтобы получить полный список, введите такую команду:
Mongrel_rails start -h.
Запуск в стандартном режиме — это хорошо, но рано или поздно возникнет нужда в чем-то необычном. На этот случай предусмотрены конфигурационные файлы.
Простой способ подготовить конфигурационный файл для Mongrel — воспользоваться флагом -G. Например, можно ввести такую командную строку:
Mongrel_rails start -G myconfig.yml -p 3000 -r /home/hal/docs -l my.log.
Заданные параметры будут сохранены (в формате YAML) в файле myconfig.yml (при наличии флага -G сервер завершается сразу после создания конфигурационного файла).
Для чтения параметров из конфигурационного файла задайте флаг -C:
Mongrel_rails start -С myconfig.yml.
Не употребляйте флаг -C вместе с другими. Он предполагает, что все параметры находятся в указанном файле.
Mongrel предлагает API для тонкой настройки поведения сервера. Флаг -S позволяет задать имя сценария, написанного с использованием этого API, который представляет собой небольшой язык предметной области (DSL — Domain-Specific Language). В документации приведен пример такого сценария (который добавляет обработчик для каталога, отличного от текущего):
# Файл: config/mongrel.conf.
Uri "/newstuff", :handler => DirHandler.new("/var/www/newstuff").
# Вызывается такой командой:
# mongrel_rails start -S config/mongrel.conf.
Mongrel можно использовать и так же, как WEBrick. Следующая интуитивно понятная программа прекрасно работает:
Require 'mongrel'.
Class TinyHandler < Mongrel::HttpHandler.
def process(request, response).
response.start(200) do |head,out|
head["Content-Type"] = "text/html".
out.write <<-EOF.
Это всего лишь тест...
EOF.
end.
end.
End.
Server = Mongrel::HttpServer.new("0.0.0.0", "3000").
Server.register("/stuff", TinyHandler.new).
Server.register("/other", Mongrel::DirHandler.new("./other")).
Server.run.join # Ждать в потоке сервера.
Если вы активно работаете с Mongrel, то вас может заинтересовать система GemPlugin. Это, по сути, автозагружаемые gem-пакеты, которые становятся «частью» Mongrel. Например, модуль «Mongrel cluster» позволяет легко управлять кластером серверов Mongrel.
О Mongrel можно рассказывать еще долго. Дополнительная информация о протоколировании, отладке, деталях системы подключения модулей и пр. содержится в онлайновой документации на сайте http://mongrel.rubyforge.org.
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- 58.
- 59.
- 60.
- 61.
- 62.
- 63.
- 64.
- 65.
- 66.
- 67.
- 68.
- 69.
- 70.
- 71.
- 72.
- 73.
- 74.
- 75.
- 76.
- 77.
- 78.
- 79.
- 80.
- 81.
- 82.
- 83.
- 84.
- 85.
- 86.
- 87.
- 88.
- 89.
- 90.
- 91.
- 92.
- 93.
- 94.
- 95.
- 96.
- 97.
- 98.
- 99.
- 100.
- 101.
- 102.
- 103.
- 104.
- 105.
- 106.
- 107.
- 108.
- 109.
- 110.
- 111.
- 112.
- 113.
- 114.
- 115.
- 116.
- 117.
- 118.
- 119.
- 120.
- 121.
- 122.
- 123.
- 124.
- 125.
- 126.
- 127.
- 128.
- 129.
- 130.
- 131.
- 132.
- 133.
- 134.
- 135.
- 136.
- 137.
- 138.
- 139.
- 140.
- 141.
- 142.
- 143.
- 144.
- 145.
- 146.
- 147.
- 148.
- 149.
- 150.
- 151.
- 152.
- 153.
- 154.
- 155.
- 156.
- 157.
- 158.
- 159.
- 160.
- 161.
- 162.
- 163.
- 164.
- 165.
- 166.
- 167.
- 168.
- 169.
- 170.
- 171.
- 172.
- 173.
- 174.
- 175.
- 176.
- 177.
- 178.
- 179.
- 180.
- 181.
- 182.
- 183.
- 184.
- 185.
- 186.
- 187.
- 188.
- 189.
- 190.
- 191.
- 192.
- 193.
- 194.
- 195.
- 196.
- 197.
- 198.
- 199.
- 200.
- 201.
- 202.
- 203.
- 204.
- 205.
- 206.
- 207.
- 208.
- 209.
- 210.
- 211.
- 212.
- 213.
- 214.
- 215.
- 216.
- 217.
- 218.
- 219.
- 220.
- 221.
- 222.
- 223.
- 224.
- 225.
- 226.
- 227.
- 228.
- 229.
- 230.
- 231.
- 232.
- 233.
- 234.
- 235.
- 236.
- 237.
- 238.
- 239.
- 240.
- 241.
- 242.
- 243.
- 244.
- 245.
- 246.
- 247.
- 248.
- 249.
- 250.
- 251.
- 252.
- 253.
- 254.
- 255.
- 256.
- 257.
- 258.
- 259.
- 260.
- 261.
- 262.
- 263.
- 264.
- 265.
- 266.
- 267.
- 268.
- 269.
- 270.
- 271.
- 272.
- 273.
- 274.
- 275.
- 276.
- 277.
- 278.
- 279.
- 280.
- 281.
- 282.
- 283.
- 284.
- 285.
- 286.
- 287.
- 288.
- 289.
- 290.
- 291.
- 292.
- 293.
- 294.
- 295.
- 296.
- 297.
- 298.
- 299.
- 300.
- 301.
- 302.
- 303.
- 304.
- 305.
- 306.
- 307.
- 308.
- 309.
- 310.
- 311.
- 312.
- 313.
- 314.
- 315.
- 316.
- 317.
- 318.
- 319.
- 320.
- 321.
- 322.
- 323.
- 324.
- 325.
- 326.
- 327.
- 328.
- 329.
- 330.
- 331.
- 332.
- 333.
- 334.
- 335.
- 336.
- 337.
- 338.
- 339.
- 340.
- 341.
- 342.
- 343.
- 344.
- 345.
- 346.
- 347.
- 348.
- 349.
- 350.
- 351.
- 352.
- 353.
- 354.
- 355.
- 356.
- 357.
- 358.
- 359.
- 360.
- 361.
- 362.
- 363.
- 364.
- 365.
- 366.
- 367.
- 368.
- 369.
- 370.
- 371.
- 372.
- 373.
- 374.
- 375.
- 376.
- 377.
- 378.
- 379.
- 380.
- 381.
- 382.
- 383.
- 384.
- 385.
- 386.
- 387.
- 388.
- 389.
- 390.
- 391.
- 392.
- 393.
- 394.
- 395.
- 396.
- 397.
- 398.
- 399.
- 400.
- 401.
- 402.
- 403.
- 404.
- 405.
- 406.
- 407.
- 408.
- 409.
- 410.
- 411.
- 412.
- 413.
- 414.
- 415.
- 416.
- 417.
- 418.
- 419.
- 420.
- 421.
- 422.
- 423.
- 424.
- 425.
- 426.
- 427.
- 428.
- 429.
- 430.
- 431.
- 432.
- 433.
- 434.
- 435.
- 436.
- 437.
- 438.
- 439.
- 440.
- 441.
- 442.
- 443.
- 444.
- 445.
- 446.
- 447.
- 448.
- 449.
- 450.
- 451.
- 452.
- 453.
- 454.
- 455.
- 456.
- 457.
- 458.
- 459.
- 460.
- 461.
- 462.
- 463.
- 464.
- 465.
- 466.
- 467.
- 468.
- 469.
- 470.
- 471.
- 472.
- 473.
- 474.
- 475.
- 476.
- 477.
- 478.
- 479.
- 480.
- 481.
- 482.
- 483.
- 484.
- 485.
- 486.
- 487.
- 488.
- 489.
- 490.
- 491.
- 492.
- 493.
- 494.
- 495.
- 496.
- 497.
- 498.
- 499.
- 500.
- 501.
- 502.
- 503.
- 504.
- 505.
- 506.
- 507.
- 508.
- 509.
- 510.
- 511.
- 512.
- 513.
- 514.
- 515.
- 516.
- 517.
- 518.
- 519.
- 520.
- 521.
- 522.
- 523.
- 524.
- 525.
- 526.
- 527.
- 528.
- 529.
- 530.
- 531.
- 532.
- 533.
- 534.
- 535.
- 536.
- 537.
- 538.
- 539.
- 540.
- 541.
- 542.
- 543.
- 544.
- 545.
- 546.
- 547.
- 548.
- 549.
- 550.
- 551.
- 552.
- 553.
- 554.
- 555.
- 556.
- 557.
- 558.
- 559.
- 560.
- 561.
- 562.
- 563.
- 564.
- 565.
- 566.
- 567.
- 568.
- 569.
- 570.
- 571.
- 572.
- 573.