【问题标题】:Using a Regex in the URI of a Mongrel Handler在 Mongrel 处理程序的 URI 中使用正则表达式
【发布时间】:2011-01-21 17:13:22
【问题描述】:

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

我希望 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

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

谢谢。

【问题讨论】:

    标签: ruby regex http handler mongrel


    【解决方案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 配合得很好。

    【讨论】:

    • 谢谢。这正是我所需要的。
    【解决方案2】:

    您应该考虑创建一个Rack application。机架是:

    • Ruby Web 应用程序标准
    • 由所有流行的 Ruby Web 框架内部使用(RailsMerbSinatraCampingRamaze、...)
    • 更容易扩展
    • 准备好在任何应用服务器(Mongrel、Webrick、Thin、Passenger 等)上运行

    Rack 有一个 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
    }
    

    接下来,在命令行上运行您的 Rack 应用程序:

    % rackup
    

    如果您安装了 mongrel,它将在端口 9292 上启动。完成!

    【讨论】:

      猜你喜欢
      • 2018-03-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-07-08
      • 2013-11-16
      • 1970-01-01
      相关资源
      最近更新 更多