В Ruby/Rails, как я могу кодировать/убирать специальные символы в URL-адресах?
Как мне закодировать или "убежать" от URL до того, как я буду использовать OpenURI для open(url)
?
Мы используем OpenURI для открытия удаленного URL-адреса и возврата xml:
getresult = open(url).read
Проблема заключается в том, что URL-адрес содержит текст пользователя, который содержит пробелы и другие символы, включая "+", "&", "?" и т.д. потенциально, поэтому нам необходимо безопасно избежать URL-адреса. Я видел множество примеров при использовании Net:: HTTP, но не нашел их для OpenURI.
Нам также нужно уметь избегать подобной строки, которую мы получаем в переменной сеанса, поэтому нам нужна обратная функция.
Ответы
Ответ 1
Ruby имеет встроенную библиотеку URI, а Addressable, в частности Addressable:: URI
Я предпочитаю Addressable:: URI. Он очень полно показан и обрабатывает кодировку для вас, когда вы используете метод query_values=
.
Я видел некоторые дискуссии о URI, которые переживают некоторые растущие боли, поэтому я стараюсь оставить его в покое для обработки кодирования/экранирования, пока эти вещи не будут отсортированы:
Ответ 2
Не используйте URI.escape
, поскольку он устарел в 1.9.
Активная поддержка Rails добавляет Hash#to_query
:
{foo: 'asd asdf', bar: '"<#$dfs'}.to_query
# => "bar=%22%3C%23%24dfs&foo=asd+asdf"
Кроме того, как вы можете видеть, он пытается упорядочить параметры запроса одинаково, что хорошо для кеширования HTTP.
Ответ 3
Стандартная библиотека Ruby для спасения:
require 'uri'
user_text = URI.escape(user_text)
url = "http://example.com/#{user_text}"
result = open(url).read
Подробнее в docs для модуля URI:: Escape. Он также имеет способ сделать обратный (unescape
)
Ответ 4
Главное, что вам нужно учитывать, это то, что вам нужно избегать ключей и значений отдельно до, вы составляете полный 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"}]