Comment puis-je utiliser un middleware de rack que pour certains chemins?
-
06-09-2019 - |
Question
Je voudrais avoir courir MyMiddleware
dans mon application Rack, mais seulement pour certains chemins. J'espérais utiliser Rack::Builder
ou au moins Rack::URLMap
, mais je ne peux pas tout à fait comprendre comment.
est ce que je pensais travailler, mais n'a pas:
# in my rackup file or Rails environment.rb:
map '/foo' do
use MyMiddleware, { :some => 'options' }
end
Ou, mieux encore, avec une expression rationnelle:
map /^foo/ do
use MyMiddleware, { :some => 'options' }
end
Mais map
semble exiger une application à la fin; il ne retombera pas sur le contrôle de passage à son parent. (L'erreur réelle est « undefined method 'each' for nil:NilClass
» de rack lorsque tente de tourner l'extrémité de ce bloc de do...end
dans un app
).
Y at-il un middleware là-bas qui prend un tableau de intergiciels et un chemin et ne les exécute si le chemin correspond?
La solution
Vous pourriez avoir MyMiddleware vérifier le chemin et passez pas le contrôle à la prochaine pièce de vaisselle moyenne si elle correspond.
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, vous pouvez utiliser URLMap w / o la dslness. Il ressemblerait à quelque chose comme ceci:
main_app = MainApp.new
Rack::URLMap.new '/'=>main_app, /^(foo|bar)/ => MyMiddleWare.new(main_app)
Autres conseils
Cela ne fonctionne pas parce que @app
n'existe pas dans le champ d'application droite:
# in my_app.ru or any Rack::Builder context:
@app = self
map '/foo' do
use MyMiddleware
run lambda { |env| @app.call(env) }
end
Mais cette 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
supprime le premier argument de map
de la face de la piste, de sorte qu'il n'a pas indéfiniment récursion. Malheureusement, cela signifie que, après ce préfixe de chemin est enlevé, il est peu probable que le reste du chemin sera bien correspondre à d'autres applications.
Voici un exemple:
::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
Aller à /html/xml
cause ce qui suit pour aller dans le journal:
HTML!
XML!
127.0.0.1 - - [28/May/2009 17:41:42] "GET /html/xml HTTP/1.1" 200 13 0.3626
C'est, l'application mappée à '/html'
bandes du préfixe '/html'
et l'appel correspond maintenant à l'application mappée à '/xml'
.