Как в Ruby / Rails кодировать / экранировать специальные символы в URL? - PullRequest
15 голосов
/ 11 февраля 2011

Как мне кодировать или «экранировать» URL, прежде чем я использую OpenURI для open(url)?

Мы используем OpenURI, чтобы открыть удаленный URL и вернуть xml:

getresult = open(url).read

Проблема в том, что URL содержит некоторый вводимый пользователем текст, который содержит пробелы и другие символы, в том числе потенциально "+", "&", "?" И т. Д., Поэтому нам нужно безопасно экранировать URL. Я видел много примеров при использовании Net :: HTTP, но не нашел ни одного для OpenURI.

Нам также нужно иметь возможность экранировать аналогичную строку, которую мы получаем в переменной сеанса, поэтому нам нужна обратная функция.

Ответы [ 4 ]

28 голосов
/ 29 ноября 2012

Не используйте URI.escape, поскольку оно устарело в 1.9.

Активная поддержка Rails добавляет Hash#to_query:

 {foo: 'asd asdf', bar: '"<#$dfs'}.to_query
 # => "bar=%22%3C%23%24dfs&foo=asd+asdf"

Кроме того, как вы можете видеть, он пытается упорядочить параметры запроса всегда одинаково, что хорошо для кэширования HTTP.

14 голосов
/ 11 февраля 2011

Стандартная библиотека Ruby для спасения:

require 'uri'
user_text = URI.escape(user_text)
url = "http://example.com/#{user_text}"
result = open(url).read

Подробнее см. В документах для модуля URI :: Escape .У этого также есть метод, чтобы сделать обратное (unescape)

8 голосов
/ 08 декабря 2011

Главное, что вам нужно учесть, это то, что вы должны экранировать ключи и значения отдельно до того, как вы составите полный URL.

Все методы, которые получают полный URL-адрес и впоследствии пытаются его избежать, не работают, поскольку они не могут определить, должен ли какой-либо символ & или = быть разделителем или, возможно, частью значения (или часть ключа).

Библиотека CGI, кажется, работает хорошо, за исключением символа пробела, который традиционно кодировался как +, и в настоящее время должен кодироваться как %20. Но это легко исправить.

Пожалуйста, примите во внимание следующее:

require 'cgi'

def encode_component(s)
  # The space-encoding is a problem:
  CGI.escape(s).gsub('+','%20')
end

def url_with_params(path, args = {})
  return path if args.empty?
  path + "?" + args.map do |k,v|
    "#{encode_component(k.to_s)}=#{encode_component(v.to_s)}" 
  end.join("&")
end

def params_from_url(url)
  path,query = url.split('?',2)
  return [path,{}] unless query
  q = query.split('&').inject({}) do |memo,p|
    k,v = p.split('=',2)
    memo[CGI.unescape(k)] = CGI.unescape(v)
    memo
  end
  return [path, q]
end

u = url_with_params( "http://example.com",
                            "x[1]"  => "& ?=/",
                            "2+2=4" => "true" )

# "http://example.com?x%5B1%5D=%26%20%3F%3D%2F&2%2B2%3D4=true"

params_from_url(u)
# ["http://example.com", {"x[1]"=>"& ?=/", "2+2=4"=>"true"}]
2 голосов
/ 11 февраля 2011

Ruby имеет встроенную библиотеку URI и гем Addressable , в частности Addressable :: URI

Я предпочитаю Addressable:: URI.Он очень полнофункциональный и обрабатывает кодирование для вас, когда вы используете метод query_values=.

Я видел некоторые дискуссии о том, что URI переживает некоторые проблемы с ростом, поэтому я склонен оставить его в покое для обработки кодирования / экранированияпока эти вещи не разбираются:

...