【问题标题】:What's the difference between URI.escape and CGI.escape?URI.escape 和 CGI​​.escape 有什么区别?
【发布时间】:2011-02-18 22:17:30
【问题描述】:

URI.escapeCGI.escape 有什么区别,我应该使用哪一个?

【问题讨论】:

    标签: ruby


    【解决方案1】:

    斧头和剑有什么区别,我应该使用哪个?嗯,它取决于你需要做什么。

    URI.escape 应该将字符串 (URL) 编码为所谓的“Percent-encoding”。

    CGI::escape 来自 CGI 规范,该规范描述了数据应如何在 Web 服务器和应用程序之间进行编码/解码。

    现在,假设您需要在应用中转义 URI。这是一个更具体的用例。 为此,Ruby 社区多年来一直使用URI.escapeURI.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 在规范级别上是错误的。所以我们 不会提供确切的替换。更换会因它而异 用例。

    https://bugs.ruby-lang.org/issues/4167

    不幸的是,文档中没有关于它的一个字,了解它的唯一方法是检查源代码,或者运行带有详细级别警告的脚本 (-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
    • 如果您需要使用 URI,请使用 Addressable,它提供 URL 编码、表单编码和规范化 URL。
    • 如果是 Rails 项目,请查看“How do I URL-escape a string in Rails?

    【讨论】:

    • 非常感谢您提供的信息。它确实摆脱了一些锄头测试警告。耙子和锄头往下看。
    • 很好的解释@Ernest,但问题是它不适用于我没有尝试创建的外部 URL(并且无法控制)。例如从网页中读取 URL,然后尝试访问这些 URL(需要在访问之前对其进行编码)的爬虫。
    • @amit_saxena 如果您负担得起将Addressable 作为您的宝石之一,您可以先解析 URL,f.i. rubydoc.info/gems/addressable/Addressable/URI.heuristic_parse
    • 有趣!但同样,我无法使用它从原始 url 中获取参数哈希,然后我按照您的描述对其进行编码。我的流程是:我从一些提要中获取外部 url -> 然后我需要对其进行编码 -> 传递给 http 客户端以获取内容。现在,如果我没有正确编码外部 url,基于 ruby​​ 的 HTTP 客户端将失败并出现无效的 URI 错误。
    • @amit_saxena 解析方法将返回Addressable:URL 的实例,然后您可以在其上调用所有实例方法,也许其中之一会得到您想要的结果:rubydoc.info/gems/addressable/Addressable/URI
    【解决方案2】:

    有一些小的差异,但重要的一点是 URI.escape 在 Ruby 1.9.2 中一直是 deprecated...所以使用 CGI::escapeERB::Util.url_encode

    对于那些感兴趣的人,on ruby-core 进行了长时间的讨论,其中还提到了 WEBrick::HTTPUtils.escapeWEBrick::HTTPUtils.escape_form

    【讨论】:

    【解决方案3】:

    URI.escape 采用第二个参数,可让您标记不安全的内容。请参阅 APIDock:

    http://apidock.com/ruby/CGI/escape/class

    http://apidock.com/ruby/URI/Escape/escape

    【讨论】:

    • 很好的答案@Robert Speicher。
    【解决方案4】:

    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 使其对浏览器有效。

    这些是我的外行术语,请随时更正。

    【讨论】:

      【解决方案5】:

      CGI.escape 用于转义查询字符串中的 URL 值。所有不属于 ALPHA、DIGIT、'_'、'-'、'.' 的字符和 ' ' 字符集被转义。

      但这会使网址不正确,因为网址需要包含“/”、“:”、“?”、“[”、“&”、“=”和“;”。也许还有更多我无法想象的事情。

      URI.escape 不理会这些 URL 字符,并尝试找到要转义的查询字符串键和值。然而,这真的不能依赖,因为值可以有各种字符,防止轻松逃脱。基本上,为时已晚。但是如果可以依赖简单的 URL(值中没有 '&' 和 '=' 等),则此函数可能用于转义可能不可读或非法的字符。

      一般来说——在使用 '&' 连接它们并在 '?' 之后添加它们之前,始终对各个键和值使用 CGI.escape。

      【讨论】:

        【解决方案6】:

        不同之处在于 URI.escape 不起作用...

        CGI.escape"/en/test?asd=qwe"
        => "%2Fen%2Ftest%3Fasd%3Dqwe"
        
        URI.escape"/en/test?asd=qwe"
        => "/en/test?asd=qwe"
        

        【讨论】:

        • 您选择了错误的测试用例。/、? 和 = 都是有效 URI 的一部分,因此没有转义。其他需要转义的字符,尤其是在查询字符串中应该是。
        • @GerardONeill 我选择测试用例正是为了展示 URI.escape 是如何不起作用和不可靠的。您是否建议 URI.escape 仅转义查询字符串?如果我想在其中编码 & ,它怎么知道参数值何时完成?也许这就是它过时的原因?
        • 我说的是正是。 URI 转义必须解析 URL,分离出它认为的各个参数,将它们转义,然后将它们重新组合在一起。即使这样也可能很混乱。但它并没有这样做——它只是避免在转义其他字符的同时转义一些字符,这使得它不完整。它可以用于简单的情况,特别是如果您知道您的参数不会......令人困惑。
        【解决方案7】:

        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]"

        【讨论】:

        • 但是 + 不需要在 URL 中编码它是参数的有效字符
        猜你喜欢
        • 2012-03-08
        • 1970-01-01
        • 2011-01-11
        • 2011-02-14
        • 1970-01-01
        • 2015-01-11
        • 1970-01-01
        • 2010-10-02
        • 2011-12-12
        相关资源
        最近更新 更多