2010-02-27 26 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