Wie kann ich nur eine Rack-Middleware für bestimmte Pfade verwenden?
-
06-09-2019 - |
Frage
Ich mag MyMiddleware
läuft in meinem Rack-App haben, aber nur für bestimmte Pfade. Ich hatte gehofft, Rack::Builder
zu verwenden oder zumindest Rack::URLMap
, aber ich kann nicht ganz herausfinden, wie.
Das ist, was ich dachte funktionieren würde, aber nicht:
# in my rackup file or Rails environment.rb:
map '/foo' do
use MyMiddleware, { :some => 'options' }
end
Oder, noch besser, mit einem Regexp:
map /^foo/ do
use MyMiddleware, { :some => 'options' }
end
Aber map
scheint eine App am Ende zu verlangen; es fällt zurück nicht nur auf übergeordneten Steuerelement vorbei zurück. (Der tatsächliche Fehler „undefined method 'each' for nil:NilClass
“ aus, wenn Gestell versucht das Ende dieses do...end
Blockes in eine app
einzuschalten.)
Gibt es eine Middleware aus, dass es eine Reihe von Middleware und einem Weg nimmt und läuft sie nur, wenn der Pfad entspricht?
Lösung
Sie können den Pfad MyMiddleware überprüfen und nicht die Steuerung weiter zum nächsten Stück Middleware übergeben, wenn es passt.
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
Oder Sie URLMap w / o der dslness nutzen könnten. Es würde wie folgt aussehen:
main_app = MainApp.new
Rack::URLMap.new '/'=>main_app, /^(foo|bar)/ => MyMiddleWare.new(main_app)
URLMap ist eigentlich ziemlich einfach grok .
Andere Tipps
Das funktioniert nicht, weil @app
nicht im richtigen Umfang existiert:
# in my_app.ru or any Rack::Builder context:
@app = self
map '/foo' do
use MyMiddleware
run lambda { |env| @app.call(env) }
end
Aber dieser Wille:
# 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
streift das erste Argument die Vorderseite des Wegs zum map
ab, damit es nicht endlos recurse. Leider bedeutet dies, dass nach diesem Pfadpräfix abgezogen wird, ist es unwahrscheinlich, dass der Rest des Weges richtig andere Zuordnungen übereinstimmen.
Hier ist ein Beispiel:
::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
zu /html/xml
Gehen verursacht die folgende in das Protokoll zu gehen:
HTML!
XML!
127.0.0.1 - - [28/May/2009 17:41:42] "GET /html/xml HTTP/1.1" 200 13 0.3626
Das heißt, die App abgebildet Streifen des '/html'
Präfix '/html'
und den Anruf jetzt passt die App '/xml'
abgebildet.