【问题标题】:How to URL encode a string in Ruby如何在 Ruby 中对字符串进行 URL 编码
【发布时间】:2011-10-06 13:13:27
【问题描述】:

我如何URI::encode 一个类似的字符串:

\x12\x34\x56\x78\x9a\xbc\xde\xf1\x23\x45\x67\x89\xab\xcd\xef\x12\x34\x56\x78\x9a

以如下格式获取它:

%124Vx%9A%BC%DE%F1%23Eg%89%AB%CD%EF%124Vx%9A

根据 RFC 1738?

这是我尝试过的:

irb(main):123:0> URI::encode "\x12\x34\x56\x78\x9a\xbc\xde\xf1\x23\x45\x67\x89\xab\xcd\xef\x12\x34\x56\x78\x9a"
ArgumentError: invalid byte sequence in UTF-8
    from /usr/local/lib/ruby/1.9.1/uri/common.rb:219:in `gsub'
    from /usr/local/lib/ruby/1.9.1/uri/common.rb:219:in `escape'
    from /usr/local/lib/ruby/1.9.1/uri/common.rb:505:in `escape'
    from (irb):123
    from /usr/local/bin/irb:12:in `<main>'

还有:

irb(main):126:0> CGI::escape "\x12\x34\x56\x78\x9a\xbc\xde\xf1\x23\x45\x67\x89\xab\xcd\xef\x12\x34\x56\x78\x9a"
ArgumentError: invalid byte sequence in UTF-8
    from /usr/local/lib/ruby/1.9.1/cgi/util.rb:7:in `gsub'
    from /usr/local/lib/ruby/1.9.1/cgi/util.rb:7:in `escape'
    from (irb):126
    from /usr/local/bin/irb:12:in `<main>'

我查看了有关互联网的所有信息,但没有找到一种方法来做到这一点,尽管我几乎可以肯定前几天我做到了这一点,没有任何麻烦。

【问题讨论】:

标签: ruby-on-rails ruby string uri urlencode


【解决方案1】:
str = "\x12\x34\x56\x78\x9a\xbc\xde\xf1\x23\x45\x67\x89\xab\xcd\xef\x12\x34\x56\x78\x9a".force_encoding('ASCII-8BIT')
puts CGI.escape str


=> "%124Vx%9A%BC%DE%F1%23Eg%89%AB%CD%EF%124Vx%9A"

【讨论】:

  • force_encoding('binary') 可能是一个更自我记录的选择。
  • 他们弃用了这种方法,改用 * CGI.escape * 。 ->http://www.ruby-forum.com/topic/207489#903709。你应该也可以使用URI.www_form_encode * URI.www_form_encode_component *,但我从来没有使用过这些
  • 这里不需要require 'open-uri'。你的意思是require 'uri'
  • @J-Rou,CGI.escape 可以转义整个 URL,它不会选择性地转义查询参数,例如,如果您将 'a=&amp;!@&amp;b=&amp;$^' 传递给 CGI.escape,它将使用查询分隔符转义整个内容&amp; 所以这只能用于查询值。我建议使用 addressable gem ,使用 url 更智能。
  • 我需要访问远程服务器上的文件。用 CGI 编码不起作用,但 URI.encode 做得很好。
【解决方案2】:

现在,您应该使用ERB::Util.url_encodeCGI.escape。它们之间的主要区别在于它们对空格的处理:

>> ERB::Util.url_encode("foo/bar? baz&")
=> "foo%2Fbar%3F%20baz%26"

>> CGI.escape("foo/bar? baz&")
=> "foo%2Fbar%3F+baz%26"

CGI.escape 跟在CGI/HTML forms spec 之后,并给你一个application/x-www-form-urlencoded 字符串,它要求将空格转义为+,而ERB::Util.url_encode 跟在RFC 3986 之后,这要求将它们编码为%20

有关更多讨论,请参阅“https://stackoverflow.com/questions/2824126/whats-the-difference-between-uri-escape-and-cgi-escape/13059657#13059657”。

【讨论】:

    【解决方案3】:
    str = "\x12\x34\x56\x78\x9a\xbc\xde\xf1\x23\x45\x67\x89\xab\xcd\xef\x12\x34\x56\x78\x9a"
    require 'cgi'
    CGI.escape(str)
    # => "%124Vx%9A%BC%DE%F1%23Eg%89%AB%CD%EF%124Vx%9A"
    

    取自@J-Rou 的评论

    【讨论】:

      【解决方案4】:

      您可以为此使用Addressable::URI gem:

      require 'addressable/uri'   
      string = '\x12\x34\x56\x78\x9a\xbc\xde\xf1\x23\x45\x67\x89\xab\xcd\xef\x12\x34\x56\x78\x9a'
      Addressable::URI.encode_component(string, Addressable::URI::CharacterClasses::QUERY)
      # "%5Cx12%5Cx34%5Cx56%5Cx78%5Cx9a%5Cxbc%5Cxde%5Cxf1%5Cx23%5Cx45%5Cx67%5Cx89%5Cxab%5Cxcd%5Cxef%5Cx12%5Cx34%5Cx56%5Cx78%5Cx9a" 
      

      它使用比CGI.escape 更现代的格式,例如,它正确地将空格编码为%20 而不是+ 符号,您可以在维基百科的“The application/x-www-form-urlencoded type”中阅读更多内容。

      2.1.2 :008 > CGI.escape('Hello, this is me')
       => "Hello%2C+this+is+me" 
      2.1.2 :009 > Addressable::URI.encode_component('Hello, this is me', Addressable::URI::CharacterClasses::QUERY)
       => "Hello,%20this%20is%20me" 
      

      【讨论】:

      • 如果不想使用任何宝石,也可以这样做:CGI.escape('Hello, this is me').gsub("+", "%20") =&gt; Hello%2C%20this%20is%20me"
      【解决方案5】:

      我最初只是试图从完整的 URL 字符串中转义文件名中的特殊字符,而不是路径上的特殊字符。

      ERB::Util.url_encode 不适合我使用:

      helper.send(:url_encode, "http://example.com/?a=\11\15")
      # => "http%3A%2F%2Fexample.com%2F%3Fa%3D%09%0D"
      

      根据“Why is URI.escape() marked as obsolete and where is this REGEXP::UNSAFE constant?”中的两个答案,看起来URI::RFC2396_Parser#escape 比使用URI::Escape#escape 更好。但是,它们对我的行为都是一样的:

      URI.escape("http://example.com/?a=\11\15")
      # => "http://example.com/?a=%09%0D"
      URI::Parser.new.escape("http://example.com/?a=\11\15")
      # => "http://example.com/?a=%09%0D"
      

      【讨论】:

      • 我能找到的唯一实际答案。谢谢。
      • 整个问题一团糟!感谢您提供了一些真正的启示。在找到这个之前,我至少浪费了一天的时间去追我的尾巴!
      【解决方案6】:

      我创建了一个 gem 来使 URI 编码的东西更简洁,以便在您的代码中使用。它会为您处理二进制编码。

      运行gem install uri-handler,然后使用:

      require 'uri-handler'
      
      str = "\x12\x34\x56\x78\x9a\xbc\xde\xf1\x23\x45\x67\x89\xab\xcd\xef\x12\x34\x56\x78\x9a".to_uri
      # => "%124Vx%9A%BC%DE%F1%23Eg%89%AB%CD%EF%124Vx%9A"
      

      它将 URI 转换功能添加到 String 类中。您还可以向它传递一个带有您想要使用的可选编码字符串的参数。默认情况下,如果直接 UTF-8 编码失败,它将设置为编码“二进制”。

      【讨论】:

        【解决方案7】:

        代码:

        str = "http://localhost/with spaces and spaces"
        encoded = URI::encode(str)
        puts encoded
        

        结果:

        http://localhost/with%20spaces%20and%20spaces
        

        【讨论】:

        • 如果接收服务器较旧,它可能无法很好地响应 CGI.escape。这仍然是一个有效的替代方案。
        【解决方案8】:

        如果您想“编码”一个完整的 URL 而不必考虑手动将其拆分为不同的部分,我发现以下工作方式与我过去使用 URI.encode 的方式相同:

        URI.parse(my_url).to_s
        

        【讨论】:

          猜你喜欢
          • 2014-03-27
          • 2010-09-18
          • 1970-01-01
          • 1970-01-01
          • 2011-06-12
          • 2022-03-01
          相关资源
          最近更新 更多