วิธีการเข้ารหัส URL สตริงใน Ruby


142

ฉันจะ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>'

ฉันดูทั้งหมดเกี่ยวกับอินเทอร์เน็ตและไม่พบวิธีที่จะทำเช่นนี้แม้ว่าฉันเกือบจะคิดบวกว่าในวันก่อนฉันทำสิ่งนี้โดยไม่มีปัญหาเลยก็ตาม


1
อาจมีประโยชน์ถ้าใช้ Ruby 1.9: yehudakatz.com/2010/05/05/…
apneadiving

คำตอบ:


183
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')อาจเป็นทางเลือกในการจัดทำเอกสารด้วยตนเองมากกว่า
สั้นเกินไป

63
พวกเขาเลิกใช้วิธีนี้แล้วให้ใช้ * CGI.escape* แทน -> http://www.ruby-forum.com/topic/207489#903709 คุณควรจะสามารถใช้ URI.www_form_encode* URI.www_form_encode_component* แต่ฉันไม่เคยใช้
J-Rou

2
ไม่จำเป็นต้องrequire 'open-uri'ที่นี่ คุณหมายถึงrequire 'uri'?
pje

1
@ J-Rou, CGI.escape สามารถหลีกเลี่ยง URL ทั้งหมดได้โดยจะไม่หลีกเลี่ยงพารามิเตอร์การค้นหาแบบเลือกเช่นหากคุณส่งผ่าน'a=&!@&b=&$^'ไปที่ CGI.escape มันจะหลีกเลี่ยงสิ่งทั้งหมดด้วยตัวคั่นการค้นหา&ดังนั้นจึงสามารถใช้เพื่อสืบค้นค่าเท่านั้น ฉันขอแนะนำให้ใช้addressableอัญมณีมันเป็นการทำงานอย่างชาญฉลาดกับ URL มากกว่า
Alexander.Iljushkin

ฉันต้องการเข้าถึงไฟล์บนเซิร์ฟเวอร์ระยะไกล การเข้ารหัสด้วย CGI ไม่ได้ผล แต่ URI.encode ทำงานได้ดี
Tashows

86

ปัจจุบันคุณควรใช้ERB::Util.url_encodeหรือCGI.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และให้application/x-www-form-urlencodedสตริงซึ่งต้องมีการเว้นช่องว่าง+ในขณะที่ERB::Util.url_encodeตามRFC 3986ซึ่งต้องเข้ารหัสเป็น%20ไฟล์.

ดู " ความแตกต่างระหว่าง URI.escape และ 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"

นำมาจากความคิดเห็นของ @ J-Rou


11

คุณสามารถใช้Addressable::URIอัญมณีสำหรับสิ่งนั้น:

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และไม่เป็น+เครื่องหมายคุณสามารถอ่านเพิ่มเติมได้ใน "ประเภทแอปพลิเคชัน / x-www-form-urlencoded " ใน Wikipedia

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") => Hello%2C%20this%20is%20me"หากไม่ต้องการใช้อัญมณีใด ๆ
Raccoon

6

ฉันสร้างอัญมณีเพื่อทำให้สิ่งที่เข้ารหัส 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 แบบตรงล้มเหลว


3

เดิมทีฉันพยายามหลีกเลี่ยงอักขระพิเศษในชื่อไฟล์เท่านั้นไม่ใช่บนเส้นทางจากสตริง 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"

ขึ้นอยู่กับสองคำตอบใน " ทำไมเป็น URI.escape () ทำเครื่องหมายว่าล้าสมัยและสถานที่ที่เป็น REGEXP :: นี้ไม่ปลอดภัยอย่างต่อเนื่อง? " ดูเหมือนว่าจะดีกว่าการใช้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"

3

หากคุณต้องการ "เข้ารหัส" URL แบบเต็มโดยไม่ต้องคิดแยกออกเป็นส่วนต่างๆด้วยตนเองฉันพบว่าสิ่งต่อไปนี้ทำงานในลักษณะเดียวกับที่ฉันเคยใช้URI.encode:

URI.parse(my_url).to_s

2

รหัส:

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

ผลลัพธ์:

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

หากเซิร์ฟเวอร์ผู้รับเก่าเซิร์ฟเวอร์อาจตอบสนองต่อ CGI.escape ได้ไม่ดี นี่ยังคงเป็นทางเลือกที่ถูกต้อง
cesartalves
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.