如何避免双重编码URI

时间:2015-08-05 07:09:23

标签: ruby encoding uri

如果URL未编码,则稍后会导致问题,因此我

URI.encode(url)

问题是,如果网址已经编码(无论出于何种原因),进一步对网址进行编码,使其无法使用。

除了URI.encode(URI.decode(url))之外,有没有更好的方法来确保网址只编码一次?

5 个答案:

答案 0 :(得分:4)

没有真正的方法,你只需要跟踪字符串是否已经被URI转义。如果你有一个字符串,你不知道它是否已经被URI转义,那就没有好的解决方案了。

通常,您应该在代码中的单个点进行编码。在内存中,通常不应对所有字符串进行URI转义。您应该在从URI解析组件后立即对组件进行unescape。在构造URI时,只在构造完整URI时对它们进行转义/编码。

如果你有一个字符串并且不知道它是否编码,你就不走运了;你需要保持跟踪,理想情况是确保编码发生在明确的系统边界。

答案 1 :(得分:1)

此问题的副本具有用户jordan的部分有效答案

Ruby - how to encode URL without re-encoding already encoded characters)。

  

URI.escape似乎在所有情况下都能以您想要的方式工作,除非   字符已经编码。考虑到这一点,我们可以采取   URI.encode的结果,并使用String#gsub来"取消编码"只有那些   字符。

     

下面的正则表达式查找%25(编码的%)   通过两个十六进制数字,例如, %252f返回%2f

require "uri"

DOUBLE_ESCAPED_EXPR = /%25([0-9a-f]{2})/i

def escape_uri(uri)
  URI.encode(uri).gsub(DOUBLE_ESCAPED_EXPR, '%\1')
end

puts escape_uri("https://www.example.com/url-déjà-vu")
# => https://www.example.com/url-d%C3%A9j%C3%A0-vu

它有点笨拙,但它适用于我遇到的所有问题。更好的是,它是幂等的:

URI.encode("http://example.com/#example%example")
# => "http://example.com/%23example%25example"

URI.encode(URI.encode("http://example.com/#example%example"))
# => "http://example.com/%2523example%2525example"

escape_uri("http://example.com/#example%example")
# => "http://example.com/%23example%25example"

escape_uri(escape_uri("http://example.com/#example%example"))
# => "http://example.com/%23example%25example"

答案 2 :(得分:1)

Addressable gem通常具有URI库中缺少的方法。在这种情况下,Addressable :: URI的normalized_encode方法可以解决这个问题:

weird = "https://www.example.com/this url’s weird"
# => "https://www.example.com/this url’s weird"

encoded = Addressable::URI.normalized_encode weird
# => "https://www.example.com/this%20url%E2%80%99s%20weird"

Addressable::URI.normalized_encode encoded
# => "https://www.example.com/this%20url%E2%80%99s%20weird"

参考文献: http://www.rubydoc.info/gems/addressable/2.3.5/Addressable/URI#normalized_encode-class_method

答案 3 :(得分:0)

我不确定OpenURI中包含哪种方法来执行此操作,因此只需与ternary运算符进行比较。

url == URI.encode(url) ? url : URI.encode(url)

它易读且简单。

if_this_is_a_true_value ? then_the_result_is_this : else_it_is_this

可能还有其他方法,包括检查某些字符的字符串等。但我认为为了保持简单和可读性,这是一个不错的解决方案。

答案 4 :(得分:0)

在编码之前解码URI有什么问题?为了牺牲编码安全性,您牺牲了一些性能:

uri = "www.example.com/%E5%86%99%E7%9C%9F/cats"

URI.encode(uri)

# => www.example.com/%25E5%2586%2599%25E7%259C%259F/cats

URI.encode(URI.decode(uri))

# => www.example.com/%E5%86%99%E7%9C%9F/cats

它的速度比简单编码慢两倍,但比Addressable之类的替代方法要快许多。