Yinelenen HTTP GET sorgu anahtarlarının yetkili konumu


137

HTTP GET sorgu dizesi yinelenen alanları ile davranış hakkında yetkili bilgi bulma konusunda sorun yaşıyorum

http://example.com/page?field=foo&field=bar 

ve özellikle siparişin korunup korunmadığı. Çoğu web odaklı diller foo ve bir anahtar "alan" ile ilişkili bar içeren bir dizi üretmek, ancak bu konuda yetkili bir ifade (örneğin bir RFC) var olup olmadığını bilmek istiyorum.RFC 3986 , 3.4. Queryanahtar = değer çiftlerini ifade eden bir bölüme sahiptir , ancak sipariş ve yinelenen alanların nasıl yorumlanacağı hakkında hiçbir şey söylenmez. Bu, arka uca bağımlı olduğu ve bu RFC kapsamında olmadığı için mantıklı ...

Fiili bir standart mevcut olmasına rağmen, bunun için sadece meraktan yetkili bir kaynak görmek istiyorum.


Bunu da merak ediyordum. Diğer bir şey, sorgu dizesindeki parametreleri POST gövdesindekilerle birleştirmeyle ilgili spekstir.
Thilo

Kod çiftliğinde insanlar sipariş garantisi olmadığını söylüyor. Ancak bu iş parçacığı eski ve hiç kimse hiçbir şekilde desteklemiyor: coderanch.com/t/357197/Servlets/java/getParameterValues-order
Thilo

1
Sorgu dizesinin sırasını koruyan sunucunun yanı sıra, bunları DOM (veya başka bir sabit) sırada gönderen tarayıcı hakkında da soru vardır.
Thilo

Yanıtlar:


112

Orada hiçbir spec olduğunu bu konuda. Ne istersen yapabilirsin.

Tipik yaklaşımlar şunları içerir: ilk verilen, son verilen, hepsinden oluşan dizi, hepsinin virgülüyle dize-birleştirme.

Ham isteğin:

GET /blog/posts?tag=ruby&tag=rails HTTP/1.1
Host: example.com

Ardından request.query['tag'], dile veya çerçeveye bağlı olarak neyin verileceği konusunda çeşitli seçenekler vardır :

request.query['tag'] => 'ruby'
request.query['tag'] => 'rails'
request.query['tag'] => ['ruby', 'rails']
request.query['tag'] => 'ruby,rails'

12
Sorunun yanı sıra, ['raylar', 'yakut'] (farklı düzen) seçeneği de vardır.
Thilo

2
Kesinlikle çok sayıda şey yapılabilir.
yfeldblum

7
.NET size bir dizi (bunu test zaman sipariş umurumda değil) verecek, PHP her zaman son ve Java (en azından Java tabanlı çalıştım sistem) her zaman ilk değer verecektir. stackoverflow.com/questions/1809494/…
SimonSimCity

17
Bu, HTTP Parametre Kirliliği adı verilen bir saldırıya dayanır ve OWASP tarafından analiz edilmiştir: owasp.org/images/b/ba/AppsecEU09_CarettoniDiPaola_v0.8.pdf 9. sayfada 20 sistemin bir listesini ve bunların nasıl işlendiğini açıklayan bir açıklama bulacaksınız bu konu.
SimonSimCity

1
@SimonSimCity buna ek olarak, parametre adına isteğe bağlı bir dizini olan köşeli parantez eklerseniz PHP aslında bir dizi oluşturur.
Martin Ender

14

PHP (en azından sürüm 4.4.4 ve daha yeni) için şu şekilde çalıştığını onaylayabilirsiniz:

GET /blog/posts?tag=ruby&tag=rails HTTP/1.1
Host: example.com

sonuç:

request.query['tag'] => 'rails'

Fakat

GET /blog/posts?tag[]=ruby&tag[]=rails HTTP/1.1
Host: example.com

sonuç:

request.query['tag'] => ['ruby', 'rails']

Bu davranış, GET ve POST verileri için aynıdır.


1
[]Eki gerçekten garip davranış gibi görünüyor, ama jQuery en aracılığı bağımsız değişken olarak bir Array göndermeye çalışırsanız .ajax(), o zaman otomatik olarak aynı şekilde sizin için onları ekleyeceğiz. Bu PHP kullanıcılarının yararına gibi görünüyor.
Ian Clark

4
@IanClark PHP kodlayıcıları için sezgiseldir - düz PHP'de $foo[] = 1bir diziye eklenir . Django (Python) da aynı şeyi yapıyor.
Izkata

Apache Tomcat'te virgülle birleştirilmiş dizeler döndürdüğünü doğrulayabilir.
Gaurav Ojha

8

yfeldblum'un cevabı mükemmel.

Son zamanlarda fark ettiğim beşinci davranışla ilgili bir not: Windows Phone'da, yinelenen sorgu anahtarıyla uri ile bir uygulama açmak NavigationFailed ile sonuçlanır:

System.ArgumentException: Aynı anahtara sahip bir öğe zaten eklenmişti.

Suçlu System.Windows.Navigation.UriParsingHelper.InternalUriParseQueryStringToDictionary(Uri uri, Boolean decodeResults).

Böylece sistem onu ​​istediğiniz gibi idare etmenize bile izin vermeyecek, yasaklayacak. Kendi biçiminizi (CSV, JSON, XML, ...) ve uri-escape-it'i seçebileceğiniz tek çözüm kalmıştır.


2
Bu, tasarım seçiminden ziyade bu işlevin dahili bir hatası gibi görünüyor. Büyük olasılıkla işlevi, oluşturduğu Sözlük'te yinelenen anahtarları denetlemez. Sözlükler, elbette, benzersiz anahtarlar gerektirir.
gligoran

1
Yani istemci tarayıcı - sunucu değil - bu durumda bir hata mı atıyor? Bir hata gibi görünüyor. Bu hatanın bugün hala var olup olmadığını merak ediyorum.
Jon Schneider

1
@JonSchneider Evet, istemci NavigationFailedböyle bir URI için atıyor . Ama beni affet, bu yazıdan bir ay sonra Windows (Telefon) geliştirmesini bıraktım ve macOS'a (iOS) taşındım, bu yüzden bugünlerde bu sorunu izlemek için artık yardım edemiyorum.
Cur

5

Çerçevelerin çoğu (tümü?) Hiçbir garanti sunmaz, bu yüzden rastgele sırayla iade edileceğini varsayalım.

Daima en güvenli yaklaşımı kullanın.

Örneğin, java HttpServlet arabirimi: ServletRequest.html # getParameterValues

GetParameterMap yöntemi bile parametre sırası hakkında herhangi bir söz bırakmaz (bir java.util.Map yineleyicisinin sırasına da güvenilemez.)


3

Genellikle, aşağıdaki gibi yinelenen parametre değerleri

http://example.com/page?field=foo&field=bar

bir dizi olan tek bir queryString parametresiyle sonuçlanır:

field[0]=='foo'
field[1]=='bar'

Bu davranışı ASP, ASP.NET ve PHP4'te gördüm.


tam olarak, bu fiili standarttır, ancak gördüğüm kadarıyla bunun üzerinde yetkili bir karar yoktur. Durumun bu olduğuna inanmadığım için, onu bulmakta beceriksizim.
Stefano Borini

2
Evet, muhtemelen herkes bu davranışı görmüş. Soru, bunun aslında bir yerde belirtilip belirtilmediğiydi.
Thilo

-1

Ben de aynı soruyu sordum. Sorguları ayrıştırmak ve dizgi için javascript işlevi yazıyorum. Bir sorgu dizesi yinelenen adlar veya x [] = 1 & x [] = 2 gibi köşeli ayraç ile ad olup olmadığını bilmiyorum, ancak bazı dil bu biçimi destekliyor.

Ancak Chrome ve Firefox'un yeni bir Sınıfı olduğunu URLSeachParamsve yalnızca en basit formatı desteklediğini görüyorum name=value. Sorgu dizesinde yinelenen adlar varsa get, URLSearchParamsyalnızca ilkini döndürme yöntemi .

Yani kişisel olarak, belki de en basit ve yinelenen isim URL'si gelecek için çok daha güvenlidir.


1
Sorgu dizesinde yinelenen adlar varsa, URLSearchParams öğesinin get yöntemi yalnızca ilkini döndürür. Bu doğru değil: kullanarak tüm değeri bir dizi olarak alabilirsinizURLSearchParams.getAll('x')
Blaise

@Blaise Çok teşekkür ederim, özelliği daha önce yanlış anladım.
LCB
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.