Apa cara yang tepat untuk menyandikan URL karakter Unicode?

107

Saya tahu tentang skema% uxxxx non-standar tetapi tampaknya itu bukan pilihan yang bijaksana karena skema tersebut telah ditolak oleh W3C.

Beberapa contoh menarik:

Karakter hati. Jika saya mengetik ini di browser saya:

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

Kemudian salin dan tempel, saya melihat URL ini

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

yang membuatnya tampak seperti Firefox (atau Safari) yang melakukan ini.

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

yang masuk akal, kecuali untuk hal-hal yang tidak dapat dikodekan dalam Latin-1, seperti karakter titik tiga.

Jika saya mengetik URL

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

ke browser saya lalu salin dan tempel, saya mengerti

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

kembali. Yang tampaknya merupakan hasil dari melakukan

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

yang masuk akal karena… tidak dapat dikodekan dengan Latin-1.

Tetapi kemudian tidak jelas bagi saya bagaimana browser tahu apakah akan memecahkan kode dengan UTF-8 atau Latin-1.

Karena ini sepertinya ambigu:

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

berfungsi, jadi saya tidak tahu bagaimana browser mengetahui apakah akan memecahkan kode itu dengan UTF-8 atau Latin-1.

Apa hal yang benar untuk dilakukan dengan karakter khusus yang perlu saya tangani?

Josh Gibson
sumber
19
Kedua contoh Anda dienkode sebagai UTF-8. Yang pertama tentu bukan Latin-1, mengingat panjangnya tiga byte ...
Jakob Borg
2
% E2% 99% A5 adalah hex untuk nilai byte dari "setelan hati hitam" di UTF-8 . Hati hitam itu bukan bagian dari kumpulan karakter Latin-1 .
Hawkeye Parker
Untuk melihat secara andal bagaimana dan apa yang dikodekan browser (dan banyak info berguna lainnya), gunakan alat pengembang yang terpasang di sebagian besar browser modern, atau dapatkan debugger HTTP gratis seperti Fiddler .
Hawkeye Parker

Jawaban:

65

Saya akan selalu menyandikan dalam UTF-8. Dari halaman Wikipedia tentang encoding persen :

Sintaks URI generik mengamanatkan bahwa skema URI baru yang menyediakan representasi data karakter dalam URI harus, pada dasarnya, mewakili karakter dari set yang tidak dicadangkan tanpa terjemahan, dan harus mengonversi semua karakter lain menjadi byte sesuai dengan UTF-8, lalu persen-menyandikan nilai-nilai itu. Persyaratan ini diperkenalkan pada Januari 2005 dengan publikasi RFC 3986 . Skema URI yang diperkenalkan sebelum tanggal ini tidak terpengaruh.

Sepertinya karena ada cara lain yang dapat diterima untuk melakukan pengkodean URL di masa lalu, browser mencoba beberapa metode mendekode URI, tetapi jika Anda yang melakukan pengkodean, Anda harus menggunakan UTF-8.

John Biesnecker
sumber
8
UTF-8 juga harus digunakan karena ini adalah satu-satunya pengkodean yang diizinkan oleh standar IRI yang lebih baru (RFC 3987, tools.ietf.org/html/rfc3986 ) yang menggantikan standar URL yang lebih lama.
Remy Lebeau
3
Seandainya orang lain terkejut seperti saya, teks di komentar @ RemyLebeau menyebutkan RFC3987, tetapi tautannya ke spesifikasi yang lebih lama 3896. URL yang benar jelas tools.ietf.org/html/rfc3987
tripleee
Ya, maaf soal itu. URI ditentukan oleh RFC 3986, IRI ditentukan oleh RFC 3987.
Remy Lebeau
10

Aturan umum tampaknya adalah bahwa browser menyandikan tanggapan formulir sesuai dengan jenis konten halaman tempat formulir itu disajikan. Ini adalah tebakan bahwa jika server mengirimi kami "text / xml; charset = iso-8859-1", maka server mengharapkan tanggapan kembali dalam format yang sama.

Jika Anda hanya memasukkan URL di bilah URL, maka browser tidak memiliki halaman dasar untuk bekerja dan oleh karena itu hanya perlu menebak. Jadi dalam kasus ini tampaknya melakukan utf-8 sepanjang waktu (karena kedua masukan Anda menghasilkan nilai bentuk tiga oktet).

Kebenaran yang menyedihkan adalah bahwa AFAIK tidak ada standar untuk karakter apa yang mengatur nilai dalam string kueri, atau memang karakter apa pun di URL, harus diartikan sebagai. Setidaknya dalam kasus nilai-nilai dalam string, tidak ada alasan untuk menganggap bahwa mereka selalu lakukan sesuai dengan karakter.

Ini adalah masalah yang diketahui bahwa Anda harus memberi tahu kerangka kerja server Anda kumpulan karakter mana yang Anda harapkan string kueri akan dikodekan sebagai --- misalnya, di Tomcat, Anda harus memanggil request.setEncoding () (atau metode serupa) sebelum Anda memanggil salah satu metode request.getParameter (). Kurangnya dokumentasi tentang hal ini mungkin mencerminkan kurangnya kesadaran akan masalah di antara banyak pengembang. (Saya secara teratur bertanya kepada narasumber Java apa perbedaan antara Pembaca dan InputStream, dan secara teratur mendapatkan tampilan kosong)

araqnid
sumber
6
RFC 3987 ( tools.ietf.org/html/rfc3986 ) mendefinisikan pengkodean standar - UTF-8 harus digunakan saat mengenkode karakter yang tidak diperbolehkan untuk tidak dikodekan.
Remy Lebeau
8

IRI ( RFC 3987 ) adalah standar terbaru yang menggantikan standar URI / URL ( RFC 3986 dan yang lebih lama). URI / URL tidak mendukung Unicode secara asli (yah, RFC 3986 menambahkan ketentuan untuk protokol berbasis URI / URL di masa mendatang untuk mendukungnya, tetapi tidak memperbarui RFC sebelumnya). Skema "% uXXXX" adalah ekstensi non-standar untuk mengizinkan Unicode dalam beberapa situasi, tetapi tidak diterapkan secara universal oleh semua orang. IRI, di sisi lain, sepenuhnya mendukung Unicode, dan mengharuskan teks tersebut dienkode sebagai UTF-8 sebelum kemudian dienkode persen.

Remy Lebeau
sumber
Saya ingin melihat pembaruan pada protokol sehingga unicode didukung sepenuhnya di URL, tidak hanya melalui encoding persen.
Mathieu J.
1
IRI memungkinkan karakter Unicode yang tidak dikodekan, kecuali dalam beberapa kasus di mana karakter yang dicadangkan harus dienkode.
Remy Lebeau
6

IRI tidak menggantikan URI, karena hanya URI (secara efektif, ASCII) yang diizinkan dalam beberapa konteks - termasuk HTTP.

Sebagai gantinya, Anda menentukan IRI dan itu akan diubah menjadi URI saat keluar dari kabel.

Mark Nottingham
sumber
0

Pertanyaan pertama adalah apa kebutuhan Anda? Pengodean UTF-8 adalah kompromi yang cukup bagus antara mengambil teks yang dibuat dengan editor murah dan dukungan untuk berbagai bahasa. Berkenaan dengan peramban yang mengidentifikasi pengkodean, respons (dari server web) harus memberi tahu peramban tentang pengkodean. Namun sebagian besar browser akan mencoba menebak, karena ini hilang atau salah dalam banyak kasus. Mereka menebak dengan membaca sejumlah aliran hasil untuk melihat apakah ada karakter yang tidak sesuai dalam pengkodean default. Saat ini semua browser (? Saya tidak memeriksa ini, tetapi cukup mendekati true) menggunakan utf-8 sebagai default.

Jadi gunakan utf-8 kecuali Anda memiliki alasan kuat untuk menggunakan salah satu dari banyak skema pengkodean lainnya.

Pat O
sumber