Apa yang valid dan apa yang tidak ada dalam kueri URI?

100

Latar belakang (pertanyaan di bawah)

Saya telah Googling ini bolak-balik membaca pertanyaan RFC dan SO mencoba memecahkan ini, tetapi saya masih belum mendapatkan jack.

Jadi saya kira kita hanya memilih jawaban "terbaik" dan hanya itu, atau?

Pada dasarnya intinya adalah ini.

3.4. Komponen Kueri

Komponen kueri adalah rangkaian informasi yang akan ditafsirkan oleh sumber daya.

query = *uric

Dalam komponen kueri, karakter ";", "/", "?", ":", "@", "&", "=", "+", ",", Dan "$" dicadangkan.

Hal pertama yang mengejutkan saya adalah bahwa * uric didefinisikan seperti ini

uric = reserved | unreserved | escaped

reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ","

Namun ini agak diklarifikasi oleh paragraf seperti

Kelas sintaks "yang dicadangkan" di atas merujuk ke karakter yang diizinkan dalam URI, tetapi mungkin tidak diizinkan dalam komponen tertentu dari sintaks URI generik; mereka digunakan sebagai pembatas dari komponen yang dijelaskan di Bagian 3.

Karakter dalam kumpulan "cadangan" tidak dicadangkan di semua konteks. Kumpulan karakter yang benar-benar dicadangkan dalam komponen URI tertentu ditentukan oleh komponen itu. Secara umum, karakter dicadangkan jika semantik URI berubah jika karakter diganti dengan enkode US-ASCII yang lolos.

Kutipan terakhir ini terasa agak mundur, tetapi dengan jelas menyatakan bahwa kumpulan karakter yang dicadangkan bergantung pada konteks. Namun 3.4 menyatakan bahwa semua karakter yang dicadangkan dicadangkan dalam komponen kueri, namun, satu-satunya hal yang akan mengubah semantik di sini adalah keluar dari tanda tanya (?) Karena URI tidak mendefinisikan konsep string kueri.

Pada titik ini saya sudah menyerah pada RFC sepenuhnya tetapi menemukan RFC 1738 sangat menarik.

URL HTTP mengambil bentuk:

http://<host>:<port>/<path>?<searchpart>

Dalam komponen <path> dan <searchpart>, "/", ";", "?" dicadangkan. Karakter "/" dapat digunakan dalam HTTP untuk menunjukkan struktur hierarki.

Saya menafsirkan ini setidaknya berkenaan dengan URL HTTP yang RFC 1738 menggantikan RFC 2396. Karena kueri URI tidak memiliki gagasan tentang string kueri, juga interpretasi yang dipesan tidak benar-benar memungkinkan saya untuk mendefinisikan string kueri seperti yang biasa saya lakukan lakukan sekarang.

Pertanyaan

Ini semua dimulai ketika saya ingin meneruskan daftar nomor bersama dengan permintaan sumber daya lain. Saya tidak terlalu memikirkannya, dan hanya meneruskannya sebagai nilai yang dipisahkan koma. Yang mengejutkan saya meskipun koma itu lolos. Kueri yang page.html?q=1,2,3dikodekan berubah menjadi page.html?q=1%2C2%2C3berfungsi, tetapi itu jelek dan tidak menduganya. Saat itulah saya mulai melalui RFC.

Pertanyaan pertama saya adalah, apakah mengkodekan koma benar-benar diperlukan?

Jawaban saya, menurut RFC 2396: ya, menurut RFC 1738: tidak

Kemudian saya menemukan posting terkait tentang lewatnya daftar di antara permintaan. Dimana pendekatan csv dianggap buruk. Ini muncul sebagai gantinya, (belum pernah melihat ini sebelumnya).

page.html?q=1;q=2;q=3

Pertanyaan kedua saya, apakah ini URL yang valid?

Jawaban saya, menurut RFC 2396: tidak, menurut RFC 1738: tidak (; dicadangkan)

Saya tidak memiliki masalah dengan meneruskan csv selama itu angka, tetapi ya Anda mengalami risiko harus menyandikan dan mendekode nilai bolak-balik jika koma tiba-tiba diperlukan untuk sesuatu yang lain. Pokoknya saya mencoba hal string kueri titik koma dengan ASP.NET dan hasilnya tidak seperti yang saya harapkan.

Default.aspx?a=1;a=2&b=1&a=3

Request.QueryString["a"] = "1;a=2,3"
Request.QueryString["b"] = "1"

Saya gagal untuk melihat bagaimana ini sangat berbeda dari pendekatan csv seperti ketika saya meminta "a" saya mendapatkan string dengan koma di dalamnya. ASP.NET jelas bukan implementasi referensi tetapi belum mengecewakan saya.

Tetapi yang paling penting - pertanyaan ketiga saya - di mana spesifikasi untuk ini? dan apa yang akan Anda lakukan atau yang tidak akan Anda lakukan?

John Leidegren
sumber
Bagaimana RFC 1738 bisa menggantikan RFC 2396, ketika RFC 2396 diterbitkan hampir 4 tahun kemudian?
Matthew Flaschen
1
Berkenaan dengan URL dan apa yang secara praktis masuk akal, interpretasi saya yang membuatnya. (menggantikan mungkin bukan kata yang tepat, karena telah digunakan dalam terminologi RFC untuk menghentikan RFC lama, RFC 1738 tidak merasa terlalu usang ketika itu adalah satu-satunya spesifikasi jika ditemukan yang memungkinkan Anda untuk meletakkan string kueri di bagian pencarian dari URL)
John Leidegren

Jawaban:

69

Bahwa sebuah karakter dicadangkan dalam komponen URL generik tidak berarti ia harus di-escape ketika muncul di dalam komponen atau di dalam data di komponen. Karakter juga harus didefinisikan sebagai pembatas dalam sintaks generik atau skema khusus dan tampilan karakter harus dalam data.

Standar saat ini untuk URI generik adalah RFC 3986 , yang mengatakan:

2.2. Karakter yang Dicadangkan

URI menyertakan komponen dan subkomponen yang dibatasi oleh karakter dalam set "cadangan". Karakter ini disebut "dicadangkan" karena mereka mungkin (atau mungkin tidak) didefinisikan sebagai pembatas oleh sintaks generik, oleh setiap sintaks khusus skema, atau dengan sintaks khusus implementasi dari algoritma dereferensi URI. Jika data untuk komponen URI akan bertentangan dengan tujuan karakter yang dicadangkan sebagai pemisah [penekanan ditambahkan], maka data yang bentrok harus dienkode dalam persen sebelum URI terbentuk.

   reserved = gen-delims / sub-delims

   gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"

   sub-pembatas = "!" / "$" / "&" / "'" / "(" / ")"
               / "*" / "+" / "," / ";" / "="

3.3. Komponen Path

[...]
pchar = tidak dipesan / pct-encoded / sub-delims / ":" / "@"
[...]

3.4 Komponen Kueri

[...]
      query = * (pchar / "/" / "?")

Jadi, koma secara eksplisit diperbolehkan dalam string kueri dan hanya perlu di-escape dalam data jika skema tertentu menetapkannya sebagai pemisah. Skema HTTP tidak menggunakan koma atau titik koma sebagai pemisah dalam string kueri, sehingga tidak perlu di-escape. Apakah browser mengikuti standar ini adalah masalah lain.

Menggunakan CSV seharusnya berfungsi dengan baik untuk data string, Anda hanya perlu mengikuti konvensi CSV standar dan mengutip data atau menghilangkan koma dengan garis miring terbalik.

Sedangkan untuk RFC 2396, ini juga memungkinkan koma yang tidak lolos dalam string kueri HTTP:

2.2. Karakter yang Dicadangkan

Banyak URI menyertakan komponen yang terdiri dari atau dibatasi oleh, karakter khusus tertentu. Karakter ini disebut "dicadangkan", karena penggunaannya dalam komponen URI dibatasi untuk tujuan yang dicadangkan. Jika data untuk komponen URI akan bertentangan dengan tujuan yang dicadangkan, maka data yang berkonflik tersebut harus di-escape sebelum membentuk URI.

Karena koma tidak memiliki tujuan yang dicadangkan di bawah skema HTTP, koma tidak harus di-escape dalam data. Catatan dari § 2.3 tentang karakter yang dicadangkan adalah karakter yang mengubah semantik ketika encoded persen hanya berlaku secara umum; karakter mungkin dienkode dengan persen tanpa mengubah semantik untuk skema tertentu, namun tetap dicadangkan.

outis
sumber
23

Untuk menjawab apa yang valid dalam string kueri, saya memeriksa karakter khusus mana yang diganti oleh chrome saat membuat permintaan:

Space -> %20
! -> !
" -> %22
# -> removed, marks the end of the query string
% -> %
& -> &
' -> %27
( -> (
) -> )
* -> *
+ -> + (this usually means blank when received at the server, so encode if necessary)
, -> ,
- -> -
. -> .
/ -> /
: -> :
; -> ;
< -> %3C
= -> =
> -> %3E
? -> ?
@ -> @
[ -> [
\ -> \
] -> ]
^ -> ^
_ -> _
` -> `
{ -> {
| -> |
} -> }
~ -> ~

Extended ASCII (like °) -> Every character from this set is encoded

Catatan: Itu mungkin tidak berarti Anda tidak boleh keluar dari karakter yang tidak diganti saat Anda membuat URI untuk link. Misalnya, sering kali direkomendasikan untuk tidak digunakan ~dalam URI karena masalah kompatibilitas, tetapi karakter tersebut masih valid.

Contoh lain adalah tanda tambah yang valid tetapi biasanya diperlakukan sebagai kosong yang dikodekan ketika server menerimanya sebagai bagian dari permintaan. Jadi itu harus dikodekan bahkan jika valid ketika tujuannya adalah untuk mewakili plus dan bukan spasi.

Jadi untuk menjawab apa yang harus dikodekan: Karakter dan karakter tidak valid yang ingin Anda perlakukan secara harfiah tetapi memiliki arti khusus atau dapat menyebabkan masalah di ujung server.

pengguna764754
sumber
Apakah /programming/2366260/whats-valid-and-whats-not-in-a-uri-query?param=b#1;c#2parameter kueri valid?
Sumit Jain
@SumitJain Tidak, karena #tidak bisa muncul di dalam bagian kueri URI apa adanya. Anda harus mengenkodenya sebagai %23, sehingga URI seharusnya /programming/2366260/whats-valid-and-whats-not-in-a-uri-query?param=b%231;c%232.
Dai
10

Gunakan saja ?q=1+2+3

Saya menjawab di sini pertanyaan keempat :) yang tidak ditanyakan tetapi semuanya dimulai dengan: bagaimana cara melewatkan daftar angka dengan nilai yang dipisahkan koma? Menurut saya, pendekatan terbaik adalah hanya meneruskannya dengan spasi terpisah, di mana spasi akan dikodekan ke bentuk url +. Berfungsi dengan baik, selama Anda tahu nilai dalam daftar tidak berisi spasi (sesuatu yang cenderung tidak dimiliki angka).

Nas Banov
sumber
Meskipun ini harus menjadi komentar (karena tidak menjawab pertanyaan), terima kasih. +lebih masuk akal dalam kasus khusus yang saya cari untuk menggunakan koma.
Gajus
6

halaman.html? q = 1; q = 2; q = 3

apakah ini URL yang valid?

Iya. Sudah ;dipesan, tetapi tidak oleh RFC. Konteks yang mendefinisikan komponen ini adalah definisi application/x-www-form-urlencodedjenis media, yang merupakan bagian dari standar HTML (bagian 17.13.4.1 ). Khususnya catatan licik yang disembunyikan di bagian B.2.2 :

Kami merekomendasikan bahwa pelaksana server HTTP, dan khususnya, pelaksana CGI mendukung penggunaan ";" sebagai ganti "&" untuk menyelamatkan penulis dari masalah keluarnya karakter "&" dengan cara ini.

Sayangnya banyak kerangka kerja skrip sisi server yang populer termasuk ASP.NET tidak mendukung penggunaan ini.

bobince
sumber
Jadi, meskipun ?q=1;q=2;q=3kueri itu valid, itu ambigu: beberapa kerangka kerja sisi server akan membacanya sebagai maksudnya { q: '1;q=2;q=3' }, yang lain mungkin melakukannya serupa { q: {'1', '2', '3'}}.
Nas Banov
1
Iya. Dan yang lebih buruk, HTML5 sekarang tidak menyertakan bahasa tentang ;, artinya HTML4 dan HTML5 tidak konsisten. Ugh, bahaya bahasa non-normatif dalam dokumen spesifikasi ...
sejak
@NasBanov Dan yang lain (misalnya PHP) akan menafsirkannya sebagai{ q: 3 }
Nicholas Shanks
1
@NicholasShanks - di mana PHP terlibat, semua taruhan dibatalkan! :)
Nas Banov
1

Saya ingin mencatat bahwa itu page.html?q=1&q=2&q=3adalah url yang valid juga. Ini adalah cara yang sepenuhnya sah untuk mengekspresikan array dalam string kueri. Teknologi server Anda akan menentukan bagaimana tepatnya itu disajikan.

Di ASP Klasik, Anda memeriksa Response.QueryString("q").Countdan kemudian menggunakan Response.QueryString("q")(0)(dan (1) dan (2)).

Perhatikan bahwa Anda juga melihat ini di ASP.NET Anda (saya pikir itu tidak dimaksudkan, tapi lihat):

Default.aspx?a=1;a=2&b=1&a=3

Request.QueryString["a"] = "1;a=2,3"
Request.QueryString["b"] = "1"

Perhatikan bahwa titik koma diabaikan, jadi Anda telah amenentukan dua kali, dan Anda mendapatkan nilainya dua kali, dipisahkan oleh koma. Menggunakan semua ampersand Default.aspx?a=1&a=2&b=1&a=3akan menghasilkan a"1,2,3". Tapi saya yakin ada metode untuk mendapatkan setiap elemen individu, jika elemen itu sendiri mengandung koma. Ini hanyalah properti default dari QueryString yang tidak diindeks yang menggabungkan sub-nilai bersama dengan pemisah koma.

ErikE
sumber
1

Saya memiliki masalah yang sama. URL yang ditautkan menjadi URL pihak ketiga dan mengharapkan daftar parameter dalam format page.html?q=1,2,3HANYA dan URL page.html?q=1%2C2%2C3tidak berfungsi. Saya bisa membuatnya bekerja menggunakan javascript. Mungkin bukan pendekatan terbaik tetapi dapat melihat solusinya di sini jika itu membantu siapa pun.

memotong
sumber
-3

Jika Anda mengirim karakter ENCODED ke file FLASH / SWF , maka Anda harus ENCODE karakter tersebut dua kali !! (karena pengurai Flash)

T.Todua
sumber