Sinatra / Rack`ERROR URI :: InvalidURIError:重定向错误的URI(不是URI?)`

时间:2013-02-01 23:59:02

标签: ruby escaping sinatra uri rack

我刚刚开始了我的第一个Sinatra项目,一个简单的电视节目管理网络应用程序,并希望拥有漂亮的URL。因此,当用户在搜索框中输入并提交时,我不希望拥有/?search=foobar样式的网址,并希望将其重定向到/search/foobar。这也使我能够将get '/search/:name路由与主get '/'路由分开。我已使用before过滤器实施了重定向,并正确转义了params[]变量:

before do
    if params.has_key? 'search'
        redirect to("/search/#{URI.escape(params['search'])}")
    end
end

以后我继续

get '/search/:query' do
    result = search_api params[:query]
    if result == 'null'
        # no results
    else
        result = JSON.parse(result)
        if result.key? 'shows'
            # display search results
        else
            # redirect to one single show
            # (result.keys).first is the real name of the show provided
            # by the api. It may contain special characters
            #
            # (result.keys).first #=> "Breaking Bad"
            # result.keys #=> "Breaking Bad"
            # result.key? "Breaking Bad" #=> true
            redirect to('/show/#{URI.escape((result.keys).first)}')
        end
    end
end

不幸的是,如果除了/show之外,名称中没有URI特殊字符,则重定向到%页面才有效。这也意味着没有空间。当我搜索带有空格或变音符号的东西时,例如GET/?search=Breaking%20Bad,我从Sinatra / Rack收到以下错误:

[2013-02-02 00:30:29] ERROR URI::InvalidURIError: bad URI(is not URI?): http://localhost:9393/show/Breaking Bad
    /Users/Ps0ke/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/uri/generic.rb:1202:in `rescue in merge'
    /Users/Ps0ke/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/uri/generic.rb:1199:in `merge'
    /Users/Ps0ke/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/webrick/httpresponse.rb:220:in `setup_header'
    /Users/Ps0ke/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/webrick/httpresponse.rb:150:in `send_response'
    /Users/Ps0ke/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/webrick/httpserver.rb:110:in `run'
    /Users/Ps0ke/.rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/webrick/server.rb:191:in `block in start_thread'

浏览器向我显示,它已重定向到/search/Breaking%20Bad,因此第一次重定向有效。只有在搜索产生精确命中时才会出现此“错误”,因此重定向的问题是在get '/search/:query'路径中搜索。我记得它曾经工作过一次,但在我的git历史中找不到正确的提交。

我正在运行

% gem list sinatra
sinatra (1.3.4, 1.3.3)

% gem list rack
rack (1.4.4, 1.4.1)
rack-cache (1.2)
rack-flash3 (1.0.3)
rack-protection (1.3.2, 1.2.0)
rack-ssl (1.3.2)
rack-test (0.6.2, 0.6.1)

也许有人可以告诉我:

  1. 这是好的还是坏的做法/在sinatra中有另一种方式来美化URL
  2. 如何解决这个问题,因为我认为我已经仔细逃过了一切
  3. 非常感谢您提前:))

1 个答案:

答案 0 :(得分:2)

在第

redirect to('/show/#{URI.escape((result.keys).first)}')

您使用的是单引号。这意味着不执行字符串插值,因此文字字符串/show/#{URI.escape((result.keys).first)}被用作URL,这就是它失败的原因。

为了使插值工作,你需要使用这样的双引号:

redirect to("/show/#{URI.escape((result.keys).first)}")

这会导致#{URI.escape((result.keys).first)}替换为转义的电影名称,该名称应该是有效的网址。

请注意,在第一次重定向中,您使用双引号,因此它按预期工作:

redirect to("/search/#{URI.escape(params['search'])}")