Pergunta

Eu gostaria de ter MyMiddleware prazo em meu aplicativo Rack, mas apenas para certos caminhos. Eu estava esperando para usar Rack::Builder ou pelo menos Rack::URLMap, mas eu não consigo descobrir como.

Isto é o que eu pensei que iria funcionar, mas não:

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

Ou, ainda melhor, com um Regexp:

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

Mas map parece exigir um aplicativo no final; ele não vai cair para trás em apenas passando o controle de volta ao seu pai. (O erro real é "undefined method 'each' for nil:NilClass" a partir de quando tentativas cremalheira para ligar a extremidade do referido bloco do...end num app.)

Existe um middleware lá fora, que leva uma série de middlewares e um caminho e só é executado-los se os jogos de caminho?

Foi útil?

Solução

Você poderia ter MyMiddleware verificar o caminho e não passar o controle para o próximo pedaço de middleware se ele corresponde.

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

Ou, você poderia usar URLMap w / o do dslness. Seria algo parecido com isto:

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

URLMap é realmente muito simples de grok .

Outras dicas

Isso não funciona porque @app não existe no âmbito direita:

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

Mas esta vontade:

# 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 retira o primeiro argumento para map fora da frente do caminho, para que ele não infinitamente recursiva. Infelizmente, isso significa que após esse prefixo caminho é retirado, é improvável que o resto do caminho irá corresponder adequadamente outros mapeamentos.

Aqui está um exemplo:

::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

Indo para /html/xml faz o seguinte para ir para o log:

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

Ou seja, o aplicativo mapeado para tiras '/html' do prefixo '/html' ea chamada agora coincide com o aplicativo mapeado para '/xml'.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top