Как использовать промежуточное ПО Rack только для определенных путей?

StackOverflow https://stackoverflow.com/questions/920719

  •  06-09-2019
  •  | 
  •  

Вопрос

Я хотел бы иметь MyMiddleware запустить в моем приложении Rack, но только для определенных путей.Я надеялся использовать Rack::Builder или по крайней мере Rack::URLMap, но я не совсем понимаю как.

Я думал, что это сработает, но не работает:

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

Или, еще лучше, с помощью Regexp:

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

Но map кажется, в конце требует приложение;он не будет просто передавать управление обратно своему родителю.(Фактическая ошибка: "undefined method 'each' for nil:NilClass" с того момента, как Рэк пытается положить конец этому do...end блокировать в app.)

Существует ли промежуточное программное обеспечение, которое принимает массив промежуточных программ и путь и запускает их только в том случае, если путь совпадает?

Это было полезно?

Решение

Вы можете заставить 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 без 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