【发布时间】:2011-02-18 22:17:30
【问题描述】:
URI.escape 和CGI.escape 有什么区别,我应该使用哪一个?
【问题讨论】:
标签: ruby
URI.escape 和CGI.escape 有什么区别,我应该使用哪一个?
【问题讨论】:
标签: ruby
斧头和剑有什么区别,我应该使用哪个?嗯,它取决于你需要做什么。
URI.escape 应该将字符串 (URL) 编码为所谓的“Percent-encoding”。
CGI::escape 来自 CGI 规范,该规范描述了数据应如何在 Web 服务器和应用程序之间进行编码/解码。
现在,假设您需要在应用中转义 URI。这是一个更具体的用例。
为此,Ruby 社区多年来一直使用URI.escape。 URI.escape 的问题在于它无法处理 RFC-3896 规范。
URI.escape 'http://google.com/foo?bar=at#anchor&title=My Blog & Your Blog'
# => "http://google.com/foo?bar=at%23anchor&title=My%20Blog%20&%20Your%20Blog"
URI.escape 被标记为过时:
此外,当前的 URI.encode 是简单的 gsub。但我认为应该 将 URI 拆分为组件,然后转义每个组件,最后 加入他们。
因此,当前的 URI.encode 被认为是有害的并已弃用。这会 被删除或彻底改变行为。
此时的替代品是什么?
正如我上面所说,当前的 URI.encode 在规范级别上是错误的。所以我们 不会提供确切的替换。更换会因它而异 用例。
不幸的是,文档中没有关于它的一个字,了解它的唯一方法是检查源代码,或者运行带有详细级别警告的脚本 (-wW2)(或使用一些 google-fu )。
一些proposed 使用CGI::Escape 作为查询参数,因为您无法转义整个URI:
CGI::escape 'http://google.com/foo?bar=at#anchor&title=My Blog & Your Blog'
# => "http%3A%2F%2Fgoogle.com%2Ffoo%3Fbar%3Dat%23anchor%26title%3DMy+Blog+%26+Your+Blog"
CGI::escape 应仅用于查询参数,但结果将再次违反规范。实际上最常见的用例是转义表单数据,例如在发送application/x-www-form-urlencoded POST 请求时。
还提到WEBrick::HTTPUtils.escape 并没有太大的改进(再说一遍,它只是一个简单的gsub,即IMO,甚至比URI.escape 更糟糕的选择):
WEBrick::HTTPUtils.escape 'http://google.com/foo?bar=at#anchor&title=My Blog & Your Blog'
# => "http://google.com/foo?bar=at%23anchor&title=My%20Blog%20&%20Your%20Blog"
最接近规范的似乎是Addressable gem:
require 'addressable/uri'
Addressable::URI.escape 'http://google.com/foo?bar=at#anchor&title=My Blog & Your Blog'
# => "http://google.com/foo?bar=at#anchor&title=My%20Blog%20&%20Your%20Blog"
请注意,与之前的所有选项不同,Addressable 不会转义 #,这是预期的行为。您希望将 # 哈希保留在 URI 路径中,而不是保留在 URI 查询中。
剩下的唯一问题是我们没有正确地转义查询参数,这使我们得出结论:我们不应该对整个 URI 使用单一方法,因为(到目前为止)还没有完美的解决方案。
如您所见,& 并未从“我的博客和您的博客”中逃脱。我们需要对查询参数使用不同形式的转义,用户可以在 URL 中放置具有特殊含义的不同字符。输入 URL 编码。 URL 编码应该用于每个“可疑”查询值,类似于 ERB::Util.url_encode 所做的:
ERB::Util.url_encode "My Blod & Your Blog"
# => "My%20Blod%20%26%20Your%20Blog""
这很酷,但我们已经需要 Addressable:
uri = Addressable::URI.parse("http://www.go.com/foo")
# => #<Addressable::URI:0x186feb0 URI:http://www.go.com/foo>
uri.query_values = {title: "My Blog & Your Blog"}
uri.normalize.to_s
# => "http://www.go.com/foo?title=My%20Blog%20%26%20Your%20Blog"
结论:
URI.escape 或类似名称CGI::escape
【讨论】:
Addressable 作为您的宝石之一,您可以先解析 URL,f.i. rubydoc.info/gems/addressable/Addressable/URI.heuristic_parse
Addressable:URL 的实例,然后您可以在其上调用所有实例方法,也许其中之一会得到您想要的结果:rubydoc.info/gems/addressable/Addressable/URI
有一些小的差异,但重要的一点是 URI.escape 在 Ruby 1.9.2 中一直是 deprecated...所以使用 CGI::escape 或 ERB::Util.url_encode。
对于那些感兴趣的人,on ruby-core 进行了长时间的讨论,其中还提到了 WEBrick::HTTPUtils.escape 和 WEBrick::HTTPUtils.escape_form。
【讨论】:
ERB::Util.url_encode 正确使用%20 作为空格
URI.escape 采用第二个参数,可让您标记不安全的内容。请参阅 APIDock:
【讨论】:
CGI::escape 非常适合转义文本段,因此它们可以用于 url 查询参数('?' 之后的字符串)。例如,如果您想在 url 中包含包含斜杠字符的参数,您可以先 CGI::escape 该字符串,然后将其插入 url。
但是在 Rails 中您可能不会直接使用它。通常你使用hash.to_param,它会在后台使用CGI::escape。
URI::escape 适合转义未正确转义的 url。例如,某些网站在其锚标记中输出错误/未转义的 url。如果您的程序使用这些 url 来获取更多资源,OpenURI 将抱怨这些 url 无效。您需要 URI::escape 这些以使其成为有效的 url。因此它用于转义整个 URI 字符串以使其正确。用我的话说 URI::unescape 使 url 可供人类阅读,而 URI::escape 使其对浏览器有效。
这些是我的外行术语,请随时更正。
【讨论】:
CGI.escape 用于转义查询字符串中的 URL 值。所有不属于 ALPHA、DIGIT、'_'、'-'、'.' 的字符和 ' ' 字符集被转义。
但这会使网址不正确,因为网址需要包含“/”、“:”、“?”、“[”、“&”、“=”和“;”。也许还有更多我无法想象的事情。
URI.escape 不理会这些 URL 字符,并尝试找到要转义的查询字符串键和值。然而,这真的不能依赖,因为值可以有各种字符,防止轻松逃脱。基本上,为时已晚。但是如果可以依赖简单的 URL(值中没有 '&' 和 '=' 等),则此函数可能用于转义可能不可读或非法的字符。
一般来说——在使用 '&' 连接它们并在 '?' 之后添加它们之前,始终对各个键和值使用 CGI.escape。
【讨论】:
不同之处在于 URI.escape 不起作用...
CGI.escape"/en/test?asd=qwe"
=> "%2Fen%2Ftest%3Fasd%3Dqwe"
URI.escape"/en/test?asd=qwe"
=> "/en/test?asd=qwe"
【讨论】:
CGI.escape 不适用于 OpenProject API。它编码了 [],: 而不是 +。我一起破解了这个,到目前为止它似乎对 OpenProject 的 API 有效。但我确定它缺少一些.gsub。它可能几乎和 URI.escape 一样糟糕,但它不会给你带来过时的错误。
class XXX
def self.encode(path)
path, query = path.split("?", 2)
return path if query.nil?
query = CGI.escape(query).gsub("%3A", ":").gsub("%3D","=").gsub("%5B","[").gsub("%5D","]").gsub("%2C",",").gsub("+","%20")
return [path,query].join("?")
end
end
XXX.encode("http://test.com/some/path?query=[box: \"cart\"]")
URI.encode("http://test.com/some/path?query=[box: \"cart\"]")
两个输出:
=> "http://test.com/some/path?query=[box:%20%22cart%22]"
=> "http://test.com/some/path?query=[box:%20%22cart%22]"
【讨论】: