Использование регулярных выражений в URI обработчика типа Mongrel - PullRequest
5 голосов
/ 27 февраля 2010

В настоящее время я использую Mongrel для разработки собственного проекта веб-приложения.

Я бы хотел, чтобы Mongrel использовал определенный Http-обработчик на основе регулярного выражения. Например, каждый раз, когда кто-то вызывает URL-адрес типа http://test/bla1.js или http://test/bla2.js, для управления запросом вызывается один и тот же обработчик Http.

Мой код выглядит примерно так:

http_server = Mongrel::Configurator.new :host => config.get("http_host") do
  listener :port => config.get("http_port") do

    uri Regexp.escape("/[a-z0-9]+.js"), :handler => BLAH::CustomHandler.new
    uri '/ui/public', :handler => Mongrel::DirHandler.new("#{$d}/public/")
    uri '/favicon', :handler => Mongrel::Error404Handler.new('')

    trap("INT") { stop }
    run
  end
end

Как видите, я пытаюсь использовать регулярное выражение вместо строки:

 uri Regexp.escape("/[a-z0-9]+.js"), :handler => BLAH::CustomHandler.new

но это не работает. Любое решение?

Спасибо за это.

Ответы [ 2 ]

2 голосов
/ 05 марта 2010

Вам следует подумать о создании приложения Rack . Стойка:

  • стандарт для веб-приложений Ruby
  • используется внутри всех популярных веб-фреймворков Ruby ( Rails , Merb , Sinatra , Camping , Ramaze , ...)
  • намного проще расширять
  • готов к запуску на любом сервере приложений (Mongrel, Webrick, Thin, Passenger, ...)

Rack имеет DSL для сопоставления URL, Rack :: Builder , что позволяет сопоставлять различные приложения Rack с определенными префиксами URL. Обычно вы сохраняете его как config.ru и запускаете его с rackup.

К сожалению, он также не допускает регулярных выражений. Но из-за простоты Rack действительно легко написать «приложение» (на самом деле lambda), которое будет вызывать правильное приложение, если URL соответствует определенному регулярному выражению.

Исходя из вашего примера, ваш config.ru может выглядеть примерно так:

require "my_custom_rack_app" # Whatever provides your MyCustomRackApp.

js_handler = MyCustomRackApp.new

default_handlers = Rack::Builder.new do
  map "/public" do
    run Rack::Directory.new("my_dir/public")
  end

  # Uncomment this to replace Rack::Builder's 404 handler with your own:
  # map "/" do
  #   run lambda { |env|
  #     [404, {"Content-Type" => "text/plain"}, ["My 404 response"]]
  #   }
  # end
end

run lambda { |env|
  if env["PATH_INFO"] =~ %r{/[a-z0-9]+\.js}
    js_handler.call(env)
  else
    default_handlers.call(env)
  end
}

Затем запустите приложение Rack из командной строки:

% rackup

Если у вас установлен mongrel, он будет запущен на порту 9292. Готово!

1 голос
/ 05 марта 2010

Вы должны внедрить новый код в часть Mongrel URIClassifier, которая в противном случае блаженно не знает URI регулярного выражения.

Ниже приведен один из способов сделать это:

#
# Must do the following BEFORE Mongrel::Configurator.new
#  Augment some of the key methods in Mongrel::URIClassifier
#  See lib/ruby/gems/XXX/gems/mongrel-1.1.5/lib/mongrel/uri_classifier.rb
#
Mongrel::URIClassifier.class_eval <<-EOS, __FILE__, __LINE__
  # Save original methods
  alias_method :register_without_regexp, :register
  alias_method :unregister_without_regexp, :unregister
  alias_method :resolve_without_regexp, :resolve

  def register(uri, handler)
    if uri.is_a?(Regexp)
      unless (@regexp_handlers ||= []).any? { |(re,h)| re==uri ? h.concat(handler) : false }
        @regexp_handlers << [ uri, handler ]
      end
    else
      # Original behaviour
      register_without_regexp(uri, handler)
    end
  end

  def unregister(uri)
    if uri.is_a?(Regexp)
      raise Mongrel::URIClassifier::RegistrationError, "\#{uri.inspect} was not registered" unless (@regexp_handlers ||= []).reject! { |(re,h)| re==uri }
    else
      # Original behaviour
      unregister_without_regexp(uri)
    end
  end

  def resolve(request_uri)
    # Try original behaviour FIRST
    result = resolve_without_regexp(request_uri)
    # If a match is not found with non-regexp URIs, try regexp
    if result[0].blank?
      (@regexp_handlers ||= []).any? { |(re,h)| (m = re.match(request_uri)) ? (result = [ m.pre_match + m.to_s, (m.to_s == Mongrel::Const::SLASH ? request_uri : m.post_match), h ]) : false }
    end
    result
  end
EOS

http_server = Mongrel::Configurator.new :host => config.get("http_host") do 
  listener :port => config.get("http_port") do 

    # Can pass a regular expression as URI
    #  (URI must be of type Regexp, no escaping please!)
    # Regular expression can match any part of an URL, start with "^/..." to
    #  anchor match at URI beginning.
    # The way this is implemented, regexp matches are only evaluated AFTER
    #  all non-regexp matches have failed (mostly for performance reasons.)
    # Also, for regexp URIs, the :in_front is ignored; adding multiple handlers
    #  to the same URI regexp behaves as if :in_front => false
    uri /^[a-z0-9]+.js/, :handler => BLAH::CustomHandler.new 

    uri '/ui/public', :handler => Mongrel::DirHandler.new("#{$d}/public/") 
    uri '/favicon', :handler => Mongrel::Error404Handler.new('') 

    trap("INT") { stop } 
    run 
  end 
end

Кажется, отлично работает с Mongrel 1.1.5.

...