2010-02-27 68 views
5

我目前正在使用Mongrel来开发自定义Web应用程序项目。在Mongrel处理程序的URI中使用正则表达式

我希望Mongrel基于正则表达式使用定义的Http处理程序。例如,每次有人调用类似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 

,但不工作。任何解决方案

谢谢你。

回答

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 

似乎只是正常工作与杂种1.1.5。

+0

谢谢。这正是我需要的。 – Benjamin 2010-03-06 00:48:29

2

您应该考虑改为创建Rack application。机架是:

  • 标准Ruby Web应用程序
  • 所有流行的Ruby Web框架内部使用
  • RailsMerbSinatraCampingRamaze ...)
  • 非常容易扩展
  • 准备运行任意应用服务器(Mongrel,Webrick,Thin,Passenger,...)

机架有一个URL映射DSL,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 
} 

接下来,在命令行中运行你的机架应用:

% rackup 

如果您已经安装了杂种,它会在9292端口启动。完成!

+0

谢谢你的回答。 – Benjamin 2010-03-06 00:42:18