【问题标题】:How do I use a Rack middleware only for certain paths?如何仅将 Rack 中间件用于某些路径?
【发布时间】:2009-05-28 13:02:37
【问题描述】:

我想让MyMiddleware 在我的 Rack 应用程序中运行,但仅限于某些路径。我希望使用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”,当 Rack 尝试将 do...end 块的末尾转换为 app 时。)

是否有中间件接受一组中间件和一个路径,并且只有在路径匹配时才运行它们?

【问题讨论】:

  • 愚蠢的错字——谢谢你的纠正,AnthonyWJones! ::羞愧地低着头::

标签: ruby rack middleware


【解决方案1】:

您可以让 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

或者,您可以使用不带 dslness 的 URLMap。它看起来像这样:

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

URLMap 实际上是pretty simple to grok

【讨论】:

  • Rack::URLMap 不幸的是不支持使用正则表达式作为位置(哈希键)部分,所以这个答案的第二部分是不正确的。
【解决方案2】:

这不起作用,因为@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::Buildermap 的第一个参数从路径的前面剥离,因此它不会无休止地递归。不幸的是,这意味着在去除该路径前缀之后,路径的其余部分不太可能正确匹配其他映射。

这是一个例子:

::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' 的应用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-01-01
    • 2019-03-31
    • 2012-12-15
    • 1970-01-01
    • 2020-05-09
    • 1970-01-01
    • 2013-03-30
    相关资源
    最近更新 更多