Cosa è valido e cosa no in una query URI?


100

Background (domanda più in basso)

Ho cercato su Google questo avanti e indietro leggendo RFC e domande SO cercando di risolverlo, ma ancora non ho ottenuto jack.

Quindi immagino che votiamo solo per la "migliore" risposta e basta, o?

Fondamentalmente si riduce a questo.

3.4. Componente di query

Il componente query è una stringa di informazioni che deve essere interpretata dalla risorsa.

query = *uric

All'interno di un componente di query, i caratteri ";", "/", "?", ":", "@", "&", "=", "+", "," E "$" sono riservati.

La prima cosa che mi lascia perplesso è che * uric è definito così

uric = reserved | unreserved | escaped

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

Ciò è tuttavia in qualche modo chiarito da paragrafi come

La classe di sintassi "riservata" sopra si riferisce a quei caratteri che sono consentiti all'interno di un URI, ma che potrebbero non essere consentiti all'interno di un particolare componente della sintassi URI generica; sono usati come delimitatori dei componenti descritti nella Sezione 3.

I caratteri nel set "riservato" non sono riservati in tutti i contesti. L'insieme di caratteri effettivamente riservato all'interno di un dato componente URI è definito da quel componente. In generale, un carattere è riservato se la semantica dell'URI cambia se il carattere viene sostituito con la sua codifica US-ASCII con escape.

Quest'ultimo estratto sembra un po 'arretrato, ma afferma chiaramente che il set di caratteri riservato dipende dal contesto. Tuttavia 3.4 afferma che tutti i caratteri riservati sono riservati all'interno di un componente di query, tuttavia, l'unica cosa che cambierebbe la semantica qui è sfuggire al punto interrogativo (?) Poiché gli URI non definiscono il concetto di stringa di query.

A questo punto ho rinunciato completamente alle RFC ma ho trovato la RFC 1738 particolarmente interessante.

Un URL HTTP assume la forma:

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

All'interno dei componenti <path> e <searchpart>, "/", ";", "?" sono riservati. Il carattere "/" può essere utilizzato all'interno di HTTP per designare una struttura gerarchica.

Lo interpreto almeno per quanto riguarda gli URL HTTP che RFC 1738 sostituisce RFC 2396. Poiché la query URI non ha la nozione di stringa di query, anche l'interpretazione di riservato non mi consente di definire stringhe di query come sono abituato facendo ormai.

Domanda

Tutto è iniziato quando ho voluto passare un elenco di numeri insieme alla richiesta di un'altra risorsa. Non ci ho pensato molto e l'ho semplicemente passato come valori separati da virgole. Con mia grande sorpresa però la virgola è stata sfuggita. La query page.html?q=1,2,3codificata trasformata in page.html?q=1%2C2%2C3esso funziona, ma è brutta e non se l'aspettava. È stato allora che ho iniziato a passare attraverso le RFC.

La mia prima domanda è semplicemente: la codifica delle virgole è davvero necessaria?

La mia risposta, secondo RFC 2396: sì, secondo RFC 1738: no

Successivamente ho trovato post correlati riguardanti il ​​passaggio di liste tra le richieste. Dove l'approccio CSV era considerato pessimo. Questo invece è apparso (non l'ho mai visto prima).

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

La mia seconda domanda, è un URL valido?

La mia risposta, secondo RFC 2396: no, secondo RFC 1738: no (; è riservato)

Non ho problemi con il passaggio di csv fintanto che sono numeri, ma sì, corri il rischio di dover codificare e decodificare i valori avanti e indietro se la virgola è improvvisamente necessaria per qualcos'altro. Comunque ho provato la stringa di query punto e virgola con ASP.NET e il risultato non era quello che mi aspettavo.

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

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

Non riesco a vedere come questo differisca notevolmente da un approccio csv poiché quando chiedo "a" ottengo una stringa con virgole. ASP.NET non è certamente un'implementazione di riferimento ma non mi ha ancora deluso.

Ma la cosa più importante - la mia terza domanda - dove sono le specifiche per questo? e cosa faresti o per quella materia non faresti?


Come può l'RFC 1738 sostituire l'RFC 2396, quando l'RFC 2396 è stato pubblicato quasi 4 anni dopo?
Matthew Flaschen

1
Per quanto riguarda gli URL e ciò che ha praticamente senso, è mia interpretazione che lo sia. (sostituire probabilmente non è la parola giusta, perché è stato usato nella terminologia RFC per vecchi RFC deprecati, RFC 1738 non sembra così deprecato quando è l'unica specifica se trovata che ti consente di inserire una stringa di query nella parte di ricerca dell'URL)
John Leidegren

Risposte:


69

Il fatto che un carattere sia riservato all'interno di un componente URL generico non significa che debba essere sottoposto a escape quando viene visualizzato all'interno del componente o all'interno dei dati nel componente. Il carattere deve anche essere definito come delimitatore all'interno della sintassi generica o specifica dello schema e l'aspetto del carattere deve essere contenuto nei dati.

Lo standard corrente per gli URI generici è RFC 3986 , che ha questo da dire:

2.2. Caratteri riservati

Gli URI includono componenti e sottocomponenti delimitati da caratteri nel set "riservato". Questi caratteri sono chiamati "riservati" perché possono (o non possono) essere definiti come delimitatori dalla sintassi generica, da ciascuna sintassi specifica dello schema o dalla sintassi specifica dell'implementazione dell'algoritmo di dereferenziazione di un URI. Se i dati per un componente URI sono in conflitto con lo scopo di un carattere riservato come delimitatore [enfasi aggiunta], i dati in conflitto devono essere codificati in percentuale prima che l'URI venga formato.

   riservato = gen-delims / sub-delims

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

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

3.3. Componente del percorso

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

3.4 Componente di query

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

Pertanto, le virgole sono esplicitamente consentite all'interno delle stringhe di query e devono essere precedute da escape nei dati solo se schemi specifici lo definiscono come delimitatore. Lo schema HTTP non utilizza la virgola o il punto e virgola come delimitatore nelle stringhe di query, quindi non è necessario eseguire l'escape. Se i browser seguono questo standard è un'altra questione.

L'uso di CSV dovrebbe funzionare bene per i dati di stringa, devi solo seguire le convenzioni CSV standard e citare i dati o sfuggire alle virgole con i backslash.

Per quanto riguarda RFC 2396, consente anche virgole senza caratteri di escape nelle stringhe di query HTTP:

2.2. Caratteri riservati

Molti URI includono componenti costituiti o delimitati da determinati caratteri speciali. Questi caratteri sono chiamati "riservati", poiché il loro utilizzo all'interno del componente URI è limitato allo scopo riservato. Se i dati per un componente URI sono in conflitto con lo scopo riservato, è necessario eseguire l'escape dei dati in conflitto prima di formare l'URI.

Poiché le virgole non hanno uno scopo riservato nello schema HTTP, non è necessario eseguire l'escape nei dati. La nota del § 2.3 sui caratteri riservati che cambiano la semantica quando codificati in percentuale si applica solo generalmente; i caratteri possono essere codificati in percentuale senza modificare la semantica per schemi specifici e tuttavia essere ancora riservati.


23

Per rispondere a ciò che è valido in una stringa di query, ho controllato quali caratteri speciali vengono sostituiti da chrome quando si effettua una richiesta:

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

Nota: questo probabilmente non significa che non dovresti eseguire l'escape di caratteri che non sono stati sostituiti quando generi URI per i link. Ad esempio, spesso si consiglia di non utilizzare ~negli URI a causa di problemi di compatibilità, ma è comunque un carattere valido.

Un altro esempio potrebbe essere il segno più che è valido ma solitamente considerato come vuoto codificato quando un server lo riceve come parte di una richiesta. Quindi dovrebbe essere codificato anche se valido quando il suo scopo è rappresentare un più e non uno spazio.

Quindi, per rispondere a ciò che dovrebbe essere codificato: caratteri non validi e caratteri che si desidera trattare letteralmente ma hanno un significato speciale o possono causare problemi sul lato server.


È /programming/2366260/whats-valid-and-whats-not-in-a-uri-query?param=b#1;c#2un parametro di query valido?
Sumit Jain

@SumitJain No, perché #non può essere visualizzato nella porzione di query di un URI così com'è. Dovrai codificarlo come %23, in modo che l'URI dovrebbe essere /programming/2366260/whats-valid-and-whats-not-in-a-uri-query?param=b%231;c%232.
Dai

10

Basta usare ?q=1+2+3

Sto rispondendo qui a una quarta domanda :) che non ha chiesto ma tutto è iniziato con: come faccio a passare l'elenco di numeri a-la valori separati da virgola? Mi sembra che l'approccio migliore sia semplicemente passarli separati da spazi, dove gli spazi verranno codificati in forma URL +. Funziona alla grande, purché tu sappia che i valori nell'elenco non contengono spazi (qualcosa che i numeri tendono a non contenere).


Anche se questo dovrebbe essere un commento (poiché non risponde alla domanda), grazie. +ha ancora più senso nel caso specifico in cui stavo cercando di utilizzare una virgola.
Gajus

6

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

è un URL valido?

Sì. Il ;è riservata, ma non da un RFC. Il contesto che definisce questo componente è la definizione del application/x-www-form-urlencodedtipo di media, che fa parte dello standard HTML (sezione 17.13.4.1 ). In particolare la nota subdola nascosta nella sezione B.2.2 :

Raccomandiamo che gli implementatori del server HTTP e, in particolare, gli implementatori CGI supportino l'uso di ";" al posto di "&" per evitare agli autori il problema di evitare i caratteri "&" in questo modo.

Sfortunatamente molti framework di scripting lato server popolari, incluso ASP.NET, non supportano questo utilizzo.


Quindi, sebbene la ?q=1;q=2;q=3query sia valida, è ambigua: alcuni framework lato server lo leggeranno come un significato { q: '1;q=2;q=3' }, altri potrebbero farlo in modo simile { q: {'1', '2', '3'}}.
Nas Banov

1
Sì. E quel che è peggio, HTML5 ora non include il linguaggio about ;, il che significa che HTML4 e HTML5 sono incoerenti. Uffa, i pericoli del linguaggio non normativo in un documento sulle specifiche ...
bobince

@NasBanov E ancora altri (ad esempio PHP) lo interpreteranno come{ q: 3 }
Nicholas Shanks

1
@NicholasShanks - dove è coinvolto PHP, tutte le scommesse sono annullate! :)
Nas Banov

1

Vorrei sottolineare che page.html?q=1&q=2&q=3è anche un URL valido. Questo è un modo del tutto legittimo per esprimere un array in una stringa di query. La tecnologia del server determinerà esattamente come viene presentato.

In ASP classico, controlli Response.QueryString("q").Counte quindi usi Response.QueryString("q")(0)(e (1) e (2)).

Nota che l'hai visto anche nel tuo ASP.NET (penso che non fosse previsto, ma guarda):

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

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

Nota che il punto e virgola viene ignorato, quindi hai a definito due volte e hai ottenuto il suo valore due volte, separato da una virgola. L'utilizzo di tutte le e commerciali Default.aspx?a=1&a=2&b=1&a=3produrrà acome "1,2,3". Ma sono sicuro che esiste un metodo per ottenere ogni singolo elemento, nel caso in cui gli elementi stessi contengano virgole. È semplicemente la proprietà predefinita della QueryString non indicizzata che concatena i sottovalori insieme ai separatori virgola.


1

Ho avuto lo stesso problema. L'URL con collegamento ipertestuale era un URL di terze parti e si aspettava un elenco di parametri page.html?q=1,2,3SOLO in formato e l'URL page.html?q=1%2C2%2C3non funzionava. Sono riuscito a farlo funzionare utilizzando javascript. Potrebbe non essere l'approccio migliore, ma puoi verificare la soluzione qui se aiuta qualcuno.


-3

Se stai inviando i caratteri ENCODED al file FLASH / SWF , dovresti ENCODE il carattere due volte !! (a causa del parser Flash)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.