O que é válido e o que não está em uma consulta de URI?

100

Histórico (questão mais abaixo)

Eu tenho pesquisado isso no Google e para trás lendo RFCs e perguntas SO tentando decifrar isso, mas ainda não entendi.

Acho que votamos na "melhor" resposta e pronto, ou?

Basicamente, tudo se resume a isso.

3.4. Componente de Consulta

O componente de consulta é uma string de informações a ser interpretada pelo recurso.

query = *uric

Em um componente de consulta, os caracteres ";", "/", "?", ":", "@", "&", "=", "+", "," E "$" são reservados.

A primeira coisa que me deixa perplexo é que * úrico é definido assim

uric = reserved | unreserved | escaped

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

No entanto, isso é um pouco esclarecido por parágrafos como

A classe de sintaxe "reservada" acima se refere aos caracteres permitidos em um URI, mas que podem não ser permitidos em um determinado componente da sintaxe genérica do URI; eles são usados ​​como delimitadores dos componentes descritos na Seção 3.

Os caracteres no conjunto "reservado" não são reservados em todos os contextos. O conjunto de caracteres realmente reservados em qualquer componente URI é definido por esse componente. Em geral, um caractere é reservado se a semântica do URI mudar se o caractere for substituído por sua codificação US-ASCII de escape.

Este último trecho parece um pouco retrógrado, mas afirma claramente que o conjunto de caracteres reservados depende do contexto. Ainda assim, 3.4 afirma que todos os caracteres reservados são reservados dentro de um componente de consulta, entretanto, a única coisa que mudaria a semântica aqui é escapar do ponto de interrogação (?), Já que URIs não definem o conceito de uma string de consulta.

Neste ponto, desisti totalmente dos RFCs, mas achei o RFC 1738 particularmente interessante.

Um URL HTTP assume o formato:

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

Nos componentes <path> e <searchpart>, "/", ";", "?" são reservados. O caractere "/" pode ser usado em HTTP para designar uma estrutura hierárquica.

Eu interpreto isso pelo menos em relação aos URLs HTTP que o RFC 1738 substitui o RFC 2396. Como a consulta URI não tem noção de uma string de consulta, a interpretação de reservado realmente não me permite definir strings de consulta como estou acostumado fazendo agora.

Questão

Isso tudo começou quando eu queria passar uma lista de números junto com a solicitação de outro recurso. Eu não pensei muito nisso e apenas passei como valores separados por vírgula. Para minha surpresa, embora a vírgula tenha escapado. A consulta page.html?q=1,2,3codificada page.html?q=1%2C2%2C3funcionou, mas é feia e não esperava. Foi quando comecei a examinar os RFCs.

Minha primeira pergunta é simplesmente: codificar vírgulas é realmente necessário?

Minha resposta, de acordo com RFC 2396: sim, de acordo com RFC 1738: não

Mais tarde encontrei posts relacionados com a passagem de listas entre pedidos. Onde a abordagem csv era considerada ruim. Em vez disso, apareceu (não vi isso antes).

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

Minha segunda pergunta, este é um URL válido?

Minha resposta, de acordo com RFC 2396: não, de acordo com RFC 1738: não (; é reservado)

Não tenho problemas em passar o csv, contanto que seja números, mas sim, você corre o risco de ter que codificar e decodificar valores para frente e para trás se a vírgula de repente for necessária para outra coisa. De qualquer forma, tentei fazer a string de consulta de ponto-e-vírgula com ASP.NET e o resultado não foi o que eu esperava.

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

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

Não consigo ver como isso difere muito de uma abordagem csv, pois quando peço "a", recebo uma string com vírgulas. ASP.NET certamente não é uma implementação de referência, mas ainda não me decepcionou.

Mas o mais importante - minha terceira pergunta - onde estão as especificações para isso? e o que você faria ou não faria?

John Leidegren
fonte
Como o RFC 1738 pode substituir o RFC 2396, quando o RFC 2396 foi publicado quase 4 anos depois?
Matthew Flaschen,
1
No que diz respeito aos URLs e ao que praticamente faz sentido, é minha interpretação que sim. (substituir provavelmente não é a palavra certa, porém, porque tem sido usada na terminologia RFC para RFCs obsoletos, RFC 1738 não parece tão obsoleto quando é a única especificação que permite que você coloque uma string de consulta na parte de pesquisa do URL)
John Leidegren,

Respostas:

69

O fato de um caractere ser reservado em um componente de URL genérico não significa que ele deva ser escapado quando aparecer dentro do componente ou nos dados do componente. O caractere também deve ser definido como um delimitador dentro da sintaxe genérica ou específica do esquema e a aparência do caractere deve estar dentro dos dados.

O padrão atual para URIs genéricos é RFC 3986 , que tem o seguinte significado:

2.2. Caracteres reservados

URIs incluem componentes e subcomponentes que são delimitados por caracteres no conjunto "reservado". Esses caracteres são chamados de "reservados" porque podem (ou não) ser definidos como delimitadores pela sintaxe genérica, por cada sintaxe específica de esquema ou pela sintaxe específica de implementação de um algoritmo de desreferenciamento de URI. Se os dados de um componente URI entrarem em conflito com o propósito de um caractere reservado como delimitador [ênfase adicionada], os dados conflitantes devem ser codificados por porcentagem antes que o URI seja formado.

   reservado = gen-delims / sub-delims

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

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

3.3. Componente de Caminho

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

3.4 Componente de Consulta

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

Assim, as vírgulas são explicitamente permitidas em strings de consulta e só precisam ter escape nos dados se esquemas específicos definem-no como um delimitador. O esquema HTTP não usa vírgula ou ponto e vírgula como delimitador em strings de consulta, portanto, não é necessário escapar o escape. Se os navegadores seguem esse padrão é outra questão.

Usar CSV deve funcionar bem para dados de string, você só precisa seguir as convenções CSV padrão e colocar os dados entre aspas ou escapar das vírgulas com barras invertidas.

Quanto ao RFC 2396, ele também permite vírgulas sem escape em strings de consulta HTTP:

2.2. Caracteres reservados

Muitos URI incluem componentes que consistem em ou são delimitados por determinados caracteres especiais. Esses caracteres são chamados de "reservados", pois seu uso no componente URI é limitado ao seu propósito reservado. Se os dados para um componente URI entrarem em conflito com a finalidade reservada, os dados conflitantes devem ser escapados antes de formar o URI.

Visto que as vírgulas não têm um propósito reservado no esquema HTTP, elas não precisam ter escape nos dados. A nota de § 2.3 sobre os caracteres reservados serem aqueles que mudam a semântica quando codificados por cento se aplica apenas em geral; os caracteres podem ser codificados por cento sem alterar a semântica para esquemas específicos e ainda assim ser reservados.

outis
fonte
23

Para responder o que é válido em uma string de consulta, verifiquei quais caracteres especiais são substituídos por cromo ao fazer uma solicitação:

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: Isso provavelmente não significa que você não deve fazer escape de caracteres que não foram substituídos ao gerar URIs para links. Por exemplo, geralmente é recomendado não usar ~em URIs devido a problemas de compatibilidade, mas ainda é um caractere válido.

Outro exemplo seria o sinal de mais que é válido, mas geralmente tratado como um branco codificado quando um servidor o recebe como parte de uma solicitação. Portanto, ele deve ser codificado mesmo que seja válido quando seu propósito é representar um sinal de mais e não um espaço.

Portanto, para responder o que deve ser codificado: Caracteres inválidos e caracteres que você deseja tratar literalmente, mas têm um significado especial ou podem causar problemas no servidor.

user764754
fonte
É /programming/2366260/whats-valid-and-whats-not-in-a-uri-query?param=b#1;c#2um parâmetro de consulta válido?
Sumit Jain
@SumitJain Não, porque #não pode aparecer dentro da parte da consulta de um URI como está. Você precisará codificá-lo como %23, para que o URI seja /programming/2366260/whats-valid-and-whats-not-in-a-uri-query?param=b%231;c%232.
Dai
10

Apenas use ?q=1+2+3

Estou respondendo aqui a uma quarta pergunta :) que não perguntou, mas tudo começou com: como passo a lista de números a-la valores separados por vírgula? Parece-me que a melhor abordagem é apenas transmiti-los separados por espaço, para onde os espaços serão codificados em forma de url +. Funciona muito bem, contanto que você saiba que os valores na lista não contêm espaços (algo que os números tendem a não conter).

Nas Banov
fonte
Embora deva ser um comentário (já que não responde à pergunta), obrigado. +faz ainda mais sentido no caso específico em que estou tentando usar uma vírgula.
Gajus
6

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

este é um URL válido?

Sim. O ;é reservado, mas não por um RFC. O contexto que define este componente é a definição do application/x-www-form-urlencodedtipo de mídia, que faz parte do padrão HTML (seção 17.13.4.1 ). Em particular, a nota furtiva escondida na seção B.2.2 :

Recomendamos que os implementadores de servidor HTTP e, em particular, os implementadores CGI suportem o uso de ";" no lugar de "&" para evitar que os autores tenham o trabalho de escapar dos caracteres "&" dessa maneira.

Infelizmente, muitas estruturas de script do lado do servidor populares, incluindo ASP.NET, não oferecem suporte a esse uso.

bobince
fonte
Portanto, embora a ?q=1;q=2;q=3consulta seja válida, ela é ambígua: alguns frameworks do lado do servidor irão interpretar seu significado { q: '1;q=2;q=3' }, outros podem fazer isso de forma semelhante { q: {'1', '2', '3'}}.
Nas Banov de
1
Sim. E o que é pior, HTML5 agora não inclui a linguagem sobre ;, o que significa que HTML4 e HTML5 são inconsistentes. Ugh, os perigos da linguagem não normativa em um documento de especificação ...
bobince
@NasBanov E ainda outros (por exemplo, PHP) interpretarão como{ q: 3 }
Nicholas Shanks
1
@NicholasShanks - onde o PHP está envolvido, todas as apostas estão canceladas! :)
Nas Banov
1

Gostaria de observar que também page.html?q=1&q=2&q=3é um URL válido. Esta é uma forma totalmente legítima de expressar uma matriz em uma string de consulta. A tecnologia do seu servidor determinará exatamente como isso é apresentado.

No Classic ASP, você verifica Response.QueryString("q").Counte depois usa Response.QueryString("q")(0)(e (1) e (2)).

Observe que você também viu isso em seu ASP.NET (acho que não era essa a intenção, mas veja):

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

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

Observe que o ponto-e-vírgula é ignorado, então você adefiniu duas vezes e obteve seu valor duas vezes, separado por uma vírgula. Usar todos os e comerciais Default.aspx?a=1&a=2&b=1&a=3resultará aem "1,2,3". Mas tenho certeza de que existe um método para obter cada elemento individual, caso os próprios elementos contenham vírgulas. É simplesmente a propriedade padrão da QueryString não indexada que concatena os subvalores junto com os separadores de vírgula.

ErikE
fonte
1

Eu tive o mesmo problema. O URL com hiperlink era um URL de terceiros e esperava uma lista de parâmetros page.html?q=1,2,3SOMENTE no formato e o URL page.html?q=1%2C2%2C3não funcionou. Consegui fazê-lo funcionar usando javascript. Pode não ser a melhor abordagem, mas pode verificar a solução aqui se ajudar alguém.

golpear
fonte
-3

Se você está enviando os caracteres ENCODED para o arquivo FLASH / SWF , então você deve ENCODE o caractere duas vezes !! (por causa do analisador Flash)

T.Todua
fonte