วิธีที่เหมาะสมในการเข้ารหัส URL ของอักขระ Unicode คืออะไร?


107

ฉันรู้จักโครงการ% uxxxx ที่ไม่ได้มาตรฐาน แต่ดูเหมือนจะไม่ใช่ทางเลือกที่ชาญฉลาดเนื่องจากโครงการนี้ถูกปฏิเสธโดย W3C

ตัวอย่างที่น่าสนใจ:

ตัวละครหัวใจ หากฉันพิมพ์สิ่งนี้ลงในเบราว์เซอร์ของฉัน:

http://www.google.com/search?q=♥

จากนั้นคัดลอกและวางฉันเห็น URL นี้

http://www.google.com/search?q=%E2%99%A5

ซึ่งทำให้ดูเหมือนว่า Firefox (หรือ Safari) กำลังทำสิ่งนี้

urllib.quote_plus(x.encode("latin-1"))
'%E2%99%A5'

ซึ่งสมเหตุสมผลยกเว้นสิ่งที่ไม่สามารถเข้ารหัสเป็นภาษาลาติน -1 ได้เช่นอักขระจุดสามจุด

ถ้าฉันพิมพ์ URL

http://www.google.com/search?q=…

ลงในเบราว์เซอร์ของฉันจากนั้นคัดลอกและวางฉันจะได้รับ

http://www.google.com/search?q=%E2%80%A6

กลับ. ซึ่งน่าจะเป็นผลจากการทำ

urllib.quote_plus(x.encode("utf-8"))

ซึ่งสมเหตุสมผลเนื่องจาก…ไม่สามารถเข้ารหัสด้วย Latin-1

แต่มันก็ไม่ชัดเจนสำหรับฉันว่าเบราว์เซอร์รู้ได้อย่างไรว่าจะถอดรหัสด้วย UTF-8 หรือ Latin-1

เนื่องจากสิ่งนี้ดูเหมือนจะคลุมเครือ:

In [67]: u"…".encode('utf-8').decode('latin-1')
Out[67]: u'\xc3\xa2\xc2\x80\xc2\xa6'

ใช้งานได้ดังนั้นฉันไม่รู้ว่าเบราว์เซอร์คิดอย่างไรว่าจะถอดรหัสด้วย UTF-8 หรือ Latin-1

อะไรคือสิ่งที่ถูกต้องในการทำกับตัวละครพิเศษที่ฉันต้องจัดการ?


19
ทั้งสองตัวอย่างของคุณเข้ารหัสเป็น UTF-8 ตัวแรกไม่ใช่ Latin-1 อย่างแน่นอนเนื่องจากมีความยาวสามไบต์ ...
Jakob Borg

2
% E2% 99% A5 เป็นฐานสิบหกสำหรับค่า byte ของว่า "ชุดหัวใจดำ" UTF-8 ว่าหัวใจสีดำไม่ได้เป็นส่วนหนึ่งของLatin-1 ชุดอักขระ
Hawkeye Parker

เชื่อถือได้เห็นว่าวิธีและสิ่งที่เบราว์เซอร์ที่มีการเข้ารหัส (และจำนวนมากของข้อมูลที่เป็นประโยชน์อื่น ๆ ) ให้ใช้เครื่องมือสำหรับนักพัฒนาที่สร้างขึ้นในเบราว์เซอร์ที่ทันสมัยที่สุดหรือรับฟรี HTTP ดีบักเช่นไวโอลิน
Hawkeye Parker

คำตอบ:


65

ฉันจะเข้ารหัส UTF-8 เสมอ จากหน้า Wikipedia เกี่ยวกับการเข้ารหัสเปอร์เซ็นต์ :

ไวยากรณ์ URI ทั่วไปกำหนดว่าโครงร่าง URI ใหม่ที่จัดเตรียมสำหรับการแสดงข้อมูลอักขระใน URI จะต้องมีผลแทนอักขระจากชุดที่ไม่ได้จองโดยไม่มีการแปลและควรแปลงอักขระอื่นทั้งหมดเป็นไบต์ตาม UTF-8 และจากนั้น เปอร์เซ็นต์เข้ารหัสค่าเหล่านั้น ข้อกำหนดนี้ถูกนำมาใช้ในเดือนมกราคมปี 2005 ด้วยการพิมพ์ของRFC 3986 โครงร่าง URI ที่นำมาใช้ก่อนวันที่นี้จะไม่ได้รับผลกระทบ

ดูเหมือนว่าเนื่องจากในอดีตมีวิธีอื่น ๆ ที่ได้รับการยอมรับในการเข้ารหัส URL เบราว์เซอร์จึงพยายามถอดรหัส URI หลายวิธี แต่ถ้าคุณเป็นคนหนึ่งที่ทำการเข้ารหัสคุณควรใช้ UTF-8


8
ควรใช้ UTF-8 เนื่องจากเป็นการเข้ารหัสเดียวที่อนุญาตโดยมาตรฐาน IRI ที่ใหม่กว่า (RFC 3987, tools.ietf.org/html/rfc3986 ) ซึ่งแทนที่มาตรฐาน URL ที่เก่ากว่า
Remy Lebeau

3
ในกรณีที่คนอื่นประหลาดใจเหมือนฉันข้อความในความคิดเห็นของ @ RemyLebeau กล่าวถึง RFC3987 แต่ลิงก์ไปยังข้อมูลจำเพาะรุ่นเก่า 3896 เห็นได้ชัดว่า URL ที่ถูกต้องคือtools.ietf.org/html/rfc3987
tripleee

ใช่ขอโทษด้วย URI ถูกกำหนดโดย RFC 3986, IRI ถูกกำหนดโดย RFC 3987
Remy Lebeau

10

กฎทั่วไปดูเหมือนว่าเบราว์เซอร์จะเข้ารหัสการตอบกลับแบบฟอร์มตามประเภทเนื้อหาของหน้าที่ใช้แบบฟอร์ม นี่เป็นการคาดเดาว่าหากเซิร์ฟเวอร์ส่ง "text / xml; charset = iso-8859-1" มาให้เราพวกเขาคาดว่าจะได้รับการตอบกลับในรูปแบบเดิม

หากคุณเพิ่งป้อน URL ในแถบ URL แสดงว่าเบราว์เซอร์ไม่มีหน้าฐานที่จะทำงานดังนั้นจึงต้องเดา ดังนั้นในกรณีนี้ดูเหมือนว่าจะทำ utf-8 ตลอดเวลา (เนื่องจากอินพุตทั้งสองของคุณสร้างค่าฟอร์มสามอ็อกเต็ต)

ความจริงที่น่าเศร้าก็คือ AFAIK ไม่มีมาตรฐานสำหรับอักขระที่กำหนดค่าในสตริงข้อความค้นหาหรือควรตีความอักขระใด ๆ ใน URL เป็น อย่างน้อยในกรณีของค่าในสตริงข้อความค้นหาไม่มีเหตุผลใดที่จะต้องคิดว่าค่าเหล่านี้จะต้องสอดคล้องกับอักขระ

เป็นปัญหาที่ทราบกันดีว่าคุณต้องบอกเฟรมเวิร์กเซิร์ฟเวอร์ของคุณว่าชุดอักขระใดที่คุณคาดว่าสตริงการสืบค้นจะเข้ารหัสเป็น --- ตัวอย่างเช่นใน Tomcat คุณต้องเรียก request.setEncoding () (หรือวิธีการที่คล้ายกัน) ก่อนคุณ เรียกใช้เมธอด request.getParameter () ใด ๆ การขาดแคลนเอกสารในเรื่องนี้อาจสะท้อนให้เห็นถึงการขาดความตระหนักถึงปัญหาในหมู่นักพัฒนาซอฟต์แวร์จำนวนมาก (ฉันถามผู้ให้สัมภาษณ์ Java เป็นประจำว่าความแตกต่างระหว่าง Reader และ InputStream คืออะไรและมักจะดูว่างเปล่า)


6
RFC 3987 ( tools.ietf.org/html/rfc3986 ) กำหนดการเข้ารหัสมาตรฐาน - ต้องใช้ UTF-8 เมื่อเข้ารหัสอักขระที่ไม่ได้รับอนุญาตโดยไม่ได้เข้ารหัส
Remy Lebeau

8

IRI ( RFC 3987 ) เป็นมาตรฐานล่าสุดที่แทนที่มาตรฐาน URI / URL ( RFC 3986และเก่ากว่า) URI / URL ไม่รองรับ Unicode โดยกำเนิด (เช่นกันRFC 3986เพิ่มข้อกำหนดสำหรับโปรโตคอลที่ใช้ URI / URL ในอนาคตเพื่อรองรับ แต่จะไม่อัปเดต RFC ที่ผ่านมา) แบบแผน "% uXXXX" เป็นส่วนขยายที่ไม่ได้มาตรฐานเพื่ออนุญาตให้ใช้ Unicode ในบางสถานการณ์ แต่ทุกคนไม่สามารถใช้งานได้ในระดับสากล ในทางกลับกัน IRI สนับสนุน Unicode อย่างสมบูรณ์และกำหนดให้ข้อความนั้นเข้ารหัสเป็น UTF-8 ก่อนจากนั้นจึงเข้ารหัสเป็นเปอร์เซ็นต์


ฉันต้องการเห็นการอัปเดตโปรโตคอลเพื่อให้รองรับ Unicode อย่างสมบูรณ์ใน URL ไม่เพียง แต่ผ่านการเข้ารหัสเปอร์เซ็นต์เท่านั้น
Mathieu J.

1
IRI อนุญาตให้ใช้อักขระ Unicode ที่ไม่ได้เข้ารหัสยกเว้นในบางกรณีที่ต้องเข้ารหัสอักขระที่สงวนไว้
Remy Lebeau

6

IRI ไม่ได้แทนที่ URI เนื่องจากอนุญาตเฉพาะ URI (อย่างมีประสิทธิภาพ, ASCII) ในบางบริบท - รวมถึง HTTP

คุณระบุ IRI แทนและจะเปลี่ยนเป็น URI เมื่อออกไปข้างนอก


0

คำถามแรกคืออะไรคือความต้องการของคุณ? การเข้ารหัส UTF-8 เป็นการประนีประนอมที่ดีระหว่างการรับข้อความที่สร้างด้วยโปรแกรมแก้ไขราคาถูกและการสนับสนุนภาษาที่หลากหลาย เกี่ยวกับเบราว์เซอร์ที่ระบุการเข้ารหัสการตอบสนอง (จากเว็บเซิร์ฟเวอร์) ควรแจ้งให้เบราว์เซอร์ทราบถึงการเข้ารหัส เบราว์เซอร์ส่วนใหญ่ยังคงพยายามคาดเดาเนื่องจากอาจหายไปหรือผิดพลาดในหลาย ๆ กรณี พวกเขาเดาโดยการอ่านสตรีมผลลัพธ์จำนวนหนึ่งเพื่อดูว่ามีอักขระที่ไม่พอดีกับการเข้ารหัสเริ่มต้นหรือไม่ ขณะนี้เบราว์เซอร์ทั้งหมด (ฉันไม่ได้ตรวจสอบสิ่งนี้ แต่ใกล้เคียงกับความเป็นจริง) ใช้ utf-8 เป็นค่าเริ่มต้น

ดังนั้นใช้ utf-8 เว้นแต่คุณจะมีเหตุผลที่น่าสนใจที่จะใช้หนึ่งในรูปแบบการเข้ารหัสอื่น ๆ

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