Rack URL Mapping

2019-06-27 11:49发布

问题:

I am trying to write two kind of Rack routes. Rack allow us to write such routes like so:

app = Rack::URLMap.new('/test'  => SimpleAdapter.new,
                       '/files' => Rack::File.new('.'))

In my case, I would like to handle those routes:

  • "/" or "index"
  • "/*" in order to match any other routes

So I had trying this:

app = Rack::URLMap.new('/index' => SimpleAdapter.new,
                       '/'      => Rack::File.new('./public'))

This works well, but... I don't know how to add '/' path (as alternative of '/index' path). The path '/*' is not interpreted as a wildcard, according to my tests. Do you know how I could do?

Thanks

回答1:

You are correct that Rack::URLMap doesn't treat '*' in a path as a wildcard. The actual translation from path to regular expression looks like this:

Regexp.new("^#{Regexp.quote(location).gsub('/', '/+')}(.*)", nil, 'n')

That is, it treats any characters in the path as literals, but also matches a path with any suffix. I believe the only way for you to accomplish what you're attempting is to use a middleware instead of an endpoint. In your config.ru you might have something like this:

use SimpleAdapter
run Rack::File

And your lib/simple_adapter.rb might look something like this:

class SimpleAdapter
  SLASH_OR_INDEX = %r{/(?:index)?}
  def initialize(app)
    @app = app
  end
  def call(env)
    request = Rack::Request.new(env)
    if request.path =~ SLASH_OR_INDEX
      # return some Rack response triple...
    else
      # pass the request on down the stack:
      @app.call(env)
    end
  end
end