5

我目前正在使用 Mongrel 开发自定义 Web 应用程序项目。

我希望 Mongrel 使用基于正则表达式定义的 Http Handler。例如,每次有人调用像http://test/bla1.jshttp://test/bla2.js这样的 url 时,都会调用相同的 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

但这不起作用。有什么解决办法吗?

感谢那。

4

2 回答 2

2

You should consider creating a Rack application instead. Rack is:

  • the standard for Ruby web applications
  • used internally by all popular Ruby web frameworks (Rails, Merb, Sinatra, Camping, Ramaze, ...)
  • much easier to extend
  • ready to be run on any application server (Mongrel, Webrick, Thin, Passenger, ...)

Rack has a URL mapping DSL, Rack::Builder, which allows you to map different Rack applications to particular URL prefixes. You typically save it as config.ru, and run it with rackup.

Unfortunately, it does not allow regular expressions either. But because of the simplicity of Rack, it is really easy to write an "application" (a lambda, actually) that will call the proper app if the URL matches a certain regex.

Based on your example, your config.ru may look something like this:

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
}

Next, run your Rack app on the command line:

% rackup

If you have mongrel installed, it will be started on port 9292. Done!

于 2010-03-05T10:17:25.003 回答
1

您必须将新代码注入到 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 一起工作得很好。

于 2010-03-05T09:29:00.373 回答