Cách thích hợp để mã hóa các ký tự Unicode trong URL là gì?


107

Tôi biết về lược đồ% uxxxx không chuẩn nhưng đó có vẻ không phải là một lựa chọn khôn ngoan vì lược đồ đã bị W3C từ chối.

Một số ví dụ thú vị:

Nhân vật trái tim. Nếu tôi nhập cái này vào trình duyệt của mình:

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

Sau đó sao chép và dán nó, tôi thấy URL này

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

điều này làm cho có vẻ như Firefox (hoặc Safari) đang làm điều này.

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

điều này có ý nghĩa, ngoại trừ những thứ không thể mã hóa bằng tiếng Latinh-1, như ký tự ba chấm.

Nếu tôi nhập URL

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

vào trình duyệt của tôi, sau đó sao chép và dán, tôi nhận được

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

trở lại. Đó dường như là kết quả của việc làm

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

điều này có ý nghĩa vì… không thể được mã hóa bằng Latin-1.

Nhưng sau đó, tôi không rõ làm thế nào trình duyệt biết nên giải mã bằng UTF-8 hay Latin-1.

Vì điều này có vẻ không rõ ràng:

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

hoạt động, vì vậy tôi không biết trình duyệt tìm ra cách giải mã bằng UTF-8 hay Latin-1.

Điều đúng đắn cần làm với các ký tự đặc biệt mà tôi cần xử lý là gì?


19
Cả hai ví dụ của bạn đều được mã hóa là UTF-8. Đầu tiên chắc chắn không phải Latin-1, cho rằng đó là ba byte dài ...
Jakob Borg

2
% E2% 99% A5 là hex cho các giá trị byte của "bộ đồ màu đen" trong UTF-8 . Trái tim màu đen đó không thuộc bộ ký tự Latin-1 .
Hawkeye Parker

Để biết chính xác cách thức và trình duyệt đang mã hóa (và nhiều thông tin hữu ích khác) một cách đáng tin cậy, hãy sử dụng các công cụ dành cho nhà phát triển được tích hợp trong hầu hết các trình duyệt hiện đại hoặc tải xuống trình gỡ lỗi HTTP miễn phí như Fiddler .
Hawkeye Parker

Câu trả lời:


65

Tôi sẽ luôn mã hóa bằng UTF-8. Từ trang Wikipedia về mã hóa phần trăm :

Cú pháp URI chung quy định rằng các lược đồ URI mới cung cấp cho việc biểu diễn dữ liệu ký tự trong URI, trên thực tế, phải đại diện cho các ký tự từ tập chưa được lưu trữ mà không cần dịch và phải chuyển đổi tất cả các ký tự khác thành byte theo UTF-8, và sau đó mã hóa phần trăm các giá trị đó. Yêu cầu này được đưa ra vào tháng 1 năm 2005 với việc xuất bản RFC 3986 . Các lược đồ URI được giới thiệu trước ngày này không bị ảnh hưởng.

Có vẻ như vì có nhiều cách khác được chấp nhận để thực hiện mã hóa URL trong quá khứ, các trình duyệt sẽ thử một số phương pháp giải mã URI, nhưng nếu bạn là người thực hiện mã hóa, bạn nên sử dụng UTF-8.


8
UTF-8 cũng nên được sử dụng vì nó là kiểu mã hóa duy nhất được cho phép bởi tiêu chuẩn IRI mới hơn (RFC 3987, tools.ietf.org/html/rfc3986 ) đang thay thế tiêu chuẩn URL cũ hơn.
Remy Lebeau

3
Trong trường hợp những người khác ngạc nhiên như tôi, văn bản trong bình luận của @ RemyLebeau đề cập đến RFC3987, nhưng liên kết là đến thông số cũ hơn 3896. URL chính xác rõ ràng là tools.ietf.org/html/rfc3987
tripleee

Vâng, xin lỗi về điều đó. URI được xác định bởi RFC 3986, IRI được xác định bởi RFC 3987.
Remy Lebeau

10

Quy tắc chung dường như là các trình duyệt mã hóa phản hồi biểu mẫu theo loại nội dung của trang mà biểu mẫu được phân phát. Đây là phỏng đoán rằng nếu máy chủ gửi cho chúng tôi "text / xml; charset = iso-8859-1", thì họ mong đợi phản hồi ở định dạng tương tự.

Nếu bạn chỉ nhập một URL vào thanh URL, thì trình duyệt không có trang cơ sở để làm việc và do đó bạn chỉ phải đoán. Vì vậy, trong trường hợp này, nó dường như luôn hoạt động utf-8 (vì cả hai đầu vào của bạn đều tạo ra các giá trị dạng ba-octet).

Sự thật đáng buồn là AFAIK không có tiêu chuẩn nào cho ký tự nào đặt giá trị trong một chuỗi truy vấn, hoặc thực sự là bất kỳ ký tự nào trong URL, nên được hiểu là. Ít nhất trong trường hợp các giá trị trong chuỗi truy vấn, không có lý do gì để giả sử rằng chúng nhất thiết phải tương ứng với các ký tự.

Đó là một vấn đề đã biết mà bạn phải cho khung máy chủ của mình biết bộ ký tự nào mà bạn mong muốn chuỗi truy vấn được mã hóa --- ví dụ: trong Tomcat, bạn phải gọi request.setEncoding () (hoặc một số phương thức tương tự) trước khi bạn gọi bất kỳ phương thức request.getParameter () nào. Sự thiếu hụt tài liệu về chủ đề này có lẽ phản ánh sự thiếu nhận thức về vấn đề của nhiều nhà phát triển. (Tôi thường hỏi những người được phỏng vấn Java sự khác biệt giữa Reader và InputStream là gì, và thường xuyên nhận được những cái nhìn trống rỗng)


6
RFC 3987 ( tools.ietf.org/html/rfc3986 ) xác định mã hóa tiêu chuẩn - UTF-8 phải được sử dụng khi mã hóa các ký tự không được phép không được mã hóa.
Remy Lebeau

8

IRI ( RFC 3987 ) là tiêu chuẩn mới nhất thay thế các tiêu chuẩn URI / URL ( RFC 3986 trở lên). URI / URL không hỗ trợ Unicode (tốt, RFC 3986 bổ sung các điều khoản cho các giao thức dựa trên URI / URL trong tương lai để hỗ trợ nó, nhưng không cập nhật các RFC trong quá khứ). Lược đồ "% uXXXX" là một phần mở rộng không chuẩn để cho phép Unicode trong một số trường hợp, nhưng không phải tất cả mọi người đều triển khai phổ biến. Mặt khác, IRI hỗ trợ đầy đủ Unicode và yêu cầu văn bản phải được mã hóa dưới dạng UTF-8 trước khi được mã hóa phần trăm.


Tôi muốn thấy bản cập nhật cho các giao thức để unicode được hỗ trợ đầy đủ trong các URL, không chỉ thông qua mã hóa phần trăm.
Mathieu J.

1
IRI cho phép các ký tự Unicode chưa được mã hóa, ngoại trừ một số trường hợp phải mã hóa các ký tự dành riêng.
Remy Lebeau

6

IRI không thay thế URI, vì chỉ URI (hiệu quả, ASCII) mới được phép trong một số ngữ cảnh - bao gồm cả HTTP.

Thay vào đó, bạn chỉ định IRI và nó sẽ được chuyển đổi thành URI khi đi ra dây.


0

Câu hỏi đầu tiên là nhu cầu của bạn là gì? Mã hóa UTF-8 là sự thỏa hiệp khá tốt giữa việc lấy văn bản được tạo bằng một trình soạn thảo rẻ tiền và hỗ trợ nhiều loại ngôn ngữ. Liên quan đến việc trình duyệt xác định mã hóa, phản hồi (từ máy chủ web) sẽ cho trình duyệt biết mã hóa. Tuy nhiên, hầu hết các trình duyệt sẽ cố gắng đoán, bởi vì điều này bị thiếu hoặc sai trong rất nhiều trường hợp. Họ đoán bằng cách đọc một số lượng của luồng kết quả để xem có ký tự không phù hợp với bảng mã mặc định hay không. Hiện tại tất cả các trình duyệt (? Tôi không kiểm tra điều này, nhưng nó khá gần với true) sử dụng utf-8 làm mặc định.

Vì vậy, hãy sử dụng utf-8 trừ khi bạn có lý do thuyết phục để sử dụng một trong nhiều lược đồ mã hóa khác.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.