我想在我的机架应用MyMiddleware运行,但只针对特定路径。我希望用Rack::Builder或至少Rack::URLMap,但我不能完全弄清楚如何。

这是我的想法会工作,但不会:

# in my rackup file or Rails environment.rb:
map '/foo' do
  use MyMiddleware, { :some => 'options' }
end

或者,更好的,具有正则表达式:

map /^foo/ do
  use MyMiddleware, { :some => 'options' }
end

但是map似乎要求在最后一个应用程序;它不会退到刚才路过控制权交还给它的父。 (实际的错误是指从机架试图把这一undefined method 'each' for nil:NilClass块的端插入do...endapp”。)

是否有一个中间件,在那里,采用中间件和一个路径的阵列且仅当路径相匹配?运行它们

有帮助吗?

解决方案

您可以有MyMiddleware检查路径和不经过控制到下一个片中间件的它是否匹配。

class MyMiddleware
  def initialize app
    @app = app
  end
  def call env
    middlewary_stuff if env['PATH_INFO'] == '/foo'
    @app.call env
  end

  def middlewary_stuff
    #...
  end
end

或者,你可以使用URLMap W / O的dslness。它看起来是这样的:

main_app = MainApp.new
Rack::URLMap.new '/'=>main_app, /^(foo|bar)/ => MyMiddleWare.new(main_app)

URLMap实际上是相当简单神交

其他提示

此不起作用,因为@app不会在正确的范围存在:

# in my_app.ru or any Rack::Builder context:
@app = self
map '/foo' do
  use MyMiddleware
  run lambda { |env| @app.call(env) }
end

但是,这会:

# in my_app.ru or any Rack::Builder context:
::MAIN_RACK_APP = self
map '/foo' do
  use MyMiddleware
  run lambda { |env| ::MAIN_RACK_APP.call(env) }
end

Rack::Builder条到map断路径前面的第一个参数,所以也没有无休止递归。不幸的是,这意味着该路径前缀被剥离后,这是不可能的路径的其余部分将正确地匹配其他映射。

下面是一个例子:

::MAIN_APP = self
use Rack::ShowExceptions
use Rack::Lint
use Rack::Reloader, 0
use Rack::ContentLength

map '/html' do
  use MyContentTypeSettingMiddleware, 'text/html'
  run lambda { |env| puts 'HTML!'; ::MAIN_APP.call(env) }
end

map '/xml' do
  use MyContentTypeSettingMiddleware, 'application/xml'
  run lambda { |env| puts 'XML!'; ::MAIN_APP.call(env) }
end

map '/' do
  use ContentType, 'text/plain'
  run lambda { |env| [ 200, {}, "<p>Hello!</p>" ] }
end

/html/xml导致以下去日志:

HTML!
XML!
127.0.0.1 - - [28/May/2009 17:41:42] "GET /html/xml HTTP/1.1" 200 13 0.3626

也就是说,映射到'/html''/html'前缀和现在的呼叫的条带应用程序映射到'/xml'该应用相匹配。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top