logo
Программирование на языке Ruby

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 или где-либо еще.