Domanda

Mi piacerebbe avere run MyMiddleware nel mio rack app, ma solo per determinati percorsi. Speravo di usare Rack::Builder o almeno Rack::URLMap, ma non riesco a capire come.

Questo è quello che ho pensato avrebbe funzionato, ma non:

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

O, meglio ancora, con un Regexp:

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

Ma map sembra richiedere un app alla fine; non cadrà di nuovo in solo di passaggio il controllo al suo genitore. (L'errore effettivo è "undefined method 'each' for nil:NilClass" da quando Rack cerca di trasformare la fine di tale blocco do...end in un app.)

C'è un middleware là fuori che accetta un array di middleware e di un percorso e viene eseguito solo loro se il percorso corrisponde?

È stato utile?

Soluzione

Si potrebbe avere MyMiddleware controllare il percorso e non passare il controllo per il prossimo pezzo di ware mezzo se corrisponde.

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

In alternativa, è possibile utilizzare URLMap w / o il dslness. Sarebbe simile a questa:

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

piuttosto semplice da Grok .

Altri suggerimenti

Questo non funziona perché @app non esiste nel campo di applicazione a destra:

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

Ma questa volontà:

# 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 strisce primo argomento map la parte anteriore del percorso, in modo che non all'infinito recurse. Sfortunatamente, questo significa che dopo che prefisso del percorso è spogliato di tutto, è improbabile che il resto del percorso corrisponderà correttamente altre mappature.

Ecco un esempio:

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

Andare al /html/xml causa il seguente per andare al registro:

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

Cioè, l'applicazione mappato '/html' strisce del prefisso '/html' e la chiamata ora corrisponde l'applicazione mappato '/xml'.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top