Jak zakodować łańcuch w Rubim w adresie URL


135

Jak mam URI::encodetaki ciąg:

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

aby uzyskać to w formacie takim jak:

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

zgodnie z RFC 1738?

Oto, czego próbowałem:

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>'

Również:

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>'

Rozejrzałem się po Internecie i nie znalazłem sposobu, aby to zrobić, chociaż jestem prawie pewien, że pewnego dnia zrobiłem to bez żadnych problemów.


1
Może przydatne, jeśli używasz Ruby 1.9: yehudakatz.com/2010/05/05/…
apneadiving

Odpowiedzi:


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

2
force_encoding('binary')może być bardziej samodokumentującym się wyborem.
mu jest za krótkie

63
Zrezygnowali z tej metody, CGI.escapezamiast tego używają * *. -> http://www.ruby-forum.com/topic/207489#903709 . Powinieneś także móc używać URI.www_form_encode* URI.www_form_encode_component*, ale nigdy ich nie używałem
J-Rou,

2
Nie ma takiej potrzeby require 'open-uri'. Czy miałeś na myśli require 'uri'?
pje

1
@ J-Rou, CGI.escape może uciec przed całym adresem URL, nie powoduje wybiórczego wyjścia z parametrów zapytania, na przykład, jeśli przekażesz 'a=&!@&b=&$^'do CGI.escape, ucieknie on z całości za pomocą separatorów zapytań, &więc może to być użyte tylko do przeszukiwania wartości. Sugeruję użycie addressablegemów, praca z adresami URL jest bardziej intelektualna.
Alexander.Iljushkin

Potrzebowałem dostępu do plików na zdalnym serwerze. Kodowanie za pomocą CGI nie działało, ale URI.encode działało dobrze.
Tashows,

82

W dzisiejszych czasach powinieneś używać ERB::Util.url_encodelub CGI.escape. Podstawową różnicą między nimi jest obsługa przestrzeni:

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

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

CGI.escapejest zgodny ze specyfikacją formularzy CGI / HTML i podaje application/x-www-form-urlencodedciąg, do którego należy zastosować spacje +, natomiast jest ERB::Util.url_encodezgodny ze specyfikacją RFC 3986 , która wymaga ich zakodowania jako %20.

Aby uzyskać więcej informacji, zobacz „ Jaka jest różnica między URI.escape i CGI.escape? ”.


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

Zaczerpnięte z komentarza @ J-Rou


11

Możesz do tego użyć Addressable::URIklejnotu:

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" 

Używa nowocześniejszego formatu, niż CGI.escapenp. Poprawnie koduje spacje jako znak, %20a nie jako +znak, o czym więcej przeczytasz w artykule „ Typ application / x-www-form-urlencoded ” na Wikipedii.

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" 

Możesz też zrobić tak: CGI.escape('Hello, this is me').gsub("+", "%20") => Hello%2C%20this%20is%20me"jeśli nie chcesz używać żadnych klejnotów
Raccoon

5

Stworzyłem klejnot, aby kodowanie URI było czystsze do wykorzystania w kodzie. Dba o kodowanie binarne za Ciebie.

Uruchom gem install uri-handler, a następnie użyj:

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"

Dodaje funkcję konwersji URI do klasy String. Możesz również przekazać mu argument z opcjonalnym ciągiem kodowania, którego chcesz użyć. Domyślnie ustawia kodowanie „binarne”, jeśli proste kodowanie UTF-8 nie powiedzie się.


2

Kod:

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

Wynik:

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

Jeśli serwer odbierający jest stary, może nie odpowiadać dobrze na CGI.escape. To wciąż ważna alternatywa.
cesartalves

2

Początkowo próbowałem uciec ze znaków specjalnych tylko w nazwie pliku, a nie w ścieżce, z pełnego ciągu adresu URL.

ERB::Util.url_encode nie działa na mój użytek:

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

Na podstawie dwóch odpowiedzi w „ Dlaczego URI.escape () jest oznaczona jako przestarzała i gdzie jest ta stała REGEXP :: UNSAFE? ”, Wygląda na to, że URI::RFC2396_Parser#escapejest lepsza niż używanie URI::Escape#escape. Jednak oboje zachowują się wobec mnie tak samo:

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"

2

Jeśli chcesz „zakodować” pełny adres URL bez zastanawiania się nad ręcznym podzieleniem go na różne części, zauważyłem, że następujące elementy działają w taki sam sposób, jak wcześniej URI.encode:

URI.parse(my_url).to_s
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.