Codificando parâmetros de consulta de URL em Java

108

Como codificar parâmetros de consulta para ir em uma url em Java? Eu sei, isso parece uma pergunta óbvia e já feita.

Existem duas sutilezas das quais não tenho certeza:

  1. Os espaços devem ser codificados no url como "+" ou como "% 20"? No Chrome, se eu digitar "http://google.com/foo=?bar me", o Chrome muda para ser codificado com% 20
  2. É necessário / correto codificar dois pontos ":" como% 3B? Chrome não.

Notas:

  • java.net.URLEncoder.encodenão parece funcionar, parece que a codificação de dados deve ser enviada do formulário. Por exemplo, ele codifica o espaço em +vez de %20e codifica dois pontos, o que não é necessário.
  • java.net.URI não codifica parâmetros de consulta
Alex Black
fonte
Esta pergunta parece útil: stackoverflow.com/questions/444112/…
Alex Black
2
a estrutura da parte da consulta depende do servidor, embora a maioria espere application/x-www-form-urlencodedpares de chave / valor. Veja aqui para mais informações: ilegalargumentexception.blogspot.com/2009/12/…
McDowell

Respostas:

127

java.net.URLEncoder.encode(String s, String encoding)pode ajudar também. Ele segue a codificação do formulário HTML application/x-www-form-urlencoded.

URLEncoder.encode(query, "UTF-8");

Por outro lado, a codificação Porcentagem (também conhecida como codificação de URL ) codifica o espaço com %20. Dois pontos é um caractere reservado, então :continuará sendo dois pontos após a codificação.

Buhake Sindi
fonte
3
Eu mencionei que não acho que isso faça a codificação de url, em vez disso, codifica os dados a serem enviados por meio de um formulário. comentários?
Alex Black
Isso porque URLEncoderestá em conformidade com o application/x-www-form-urlencodedformato MIME (que é uma codificação de formulário HTML válida). Presumo que não seja isso que você está procurando.
Buhake Sindi
6
Acabei usando URLEncoder.encode e substituindo "+" por "% 20"
Alex Black
2
Ele codifica barras como "% 2F", não deveria deixar as barras de URL como estão?
golimar
6
@golimar Não, não deveria. Você deve fornecer apenas o valor do parâmetro e não a URL inteira. Considere o exemplo http://example.com/?url=http://example.com/?q=c&sort=name. Deve codificar &sort=nameou não? Não há como distinguir o valor do URL. Essa é a razão exata pela qual você precisa da codificação de valor em primeiro lugar.
Pijusn
15

EDIT: URIUtilnão está mais disponível em versões mais recentes, melhor resposta em Java - encode URL ou pelo Sr. Sindi neste tópico.


URIUtildo Apache httpclient é realmente útil, embora existam algumas alternativas

URIUtil.encodeQuery(url);

Por exemplo, ele codifica o espaço como "+" em vez de "% 20"

Ambos são perfeitamente válidos no contexto certo . Embora se você realmente preferisse, você poderia emitir uma substituição de string.

Johan Sjöberg
fonte
Eu tenho que concordar. Use o HttpClient, você será muito mais feliz.
DaShaun
Parece promissor, conseguiu um link por acaso? Estou pesquisando, mas encontrando muitos.
Alex Black
1
Este método não parece estar presente no HttpClient 4.1? hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/org/…
Alex Black
@Alex, hmm que chato, sempre usei essa rotina com bons resultados. Uma ideia é pegar o código-fonte da versão 3, já que agora eles obviamente não queriam mais mantê-lo.
Johan Sjöberg,
1
URIUtil.encodeWithinQueryé o que você usaria para codificar um parâmetro de consulta individual, que é o que a pergunta original parecia estar perguntando.
Jesse Glick
13

Infelizmente, URLEncoder.encode () não produz codificação de porcentagem válida (conforme especificado em RFC 3986 ).

URLEncoder.encode () codifica tudo perfeitamente, exceto o espaço é codificado para "+". Todos os codificadores URI Java que consegui encontrar expõem apenas métodos públicos para codificar a consulta, o fragmento, as partes do caminho, etc. - mas não expõe a codificação "bruta". Isso é lamentável, pois o fragmento e a consulta podem codificar o espaço para +, então não queremos usá-los. O caminho está codificado corretamente, mas é "normalizado" primeiro, portanto também não podemos usá-lo para codificação "genérica".

Melhor solução que eu poderia apresentar:

return URLEncoder.encode(raw, "UTF-8").replaceAll("\\+", "%20");

E se replaceAll() for muito lento para você, acho que a alternativa é rolar seu próprio codificador ...

EDITAR: Eu coloquei este código aqui primeiro, que não codifica "?", "&", "=" Corretamente:

//don't use - doesn't properly encode "?", "&", "="
new URI(null, null, null, raw, null).toString().substring(1);
Kosta
fonte
+é uma codificação perfeitamente válida de um espaço.
Lawrence Dol
@LawrenceDol é verdade, mas às vezes +pode ser interpretado incorretamente - dê uma olhada em C # blogs.msdn.microsoft.com/yangxind/2006/11/08/…
Lu55
Este. Eu comparei várias alternativas com a encodeURIComponentsaída do método Javascript , e esta foi a única correspondência exata para as que tentei (consultas com espaços, caracteres especiais turcos e alemães).
Utku Özdemir
8

Não é necessário codificar dois-pontos como% 3B na consulta, embora isso não seja ilegal.

URI         = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
query       = *( pchar / "/" / "?" )
pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
pct-encoded   = "%" HEXDIG HEXDIG
sub-delims    = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "="

Também parece que apenas espaços codificados por cento são válidos, pois duvido que o espaço seja um ALFA ou um DÍGITO

consulte a especificação URI para obter mais detalhes.

Edwin Buck
fonte
Mas fazer isso pode mudar o significado do URI, uma vez que a interpretação da string de consulta depende do servidor. Se você estiver produzindo uma application/x-www-form-urlencodedstring de consulta, qualquer uma das opções está correta. Se você estiver corrigindo um URL que o usuário digitou / colou, :deve ser deixado sozinho.
tc.
@tc. Você está certo, se dois pontos estão sendo usados ​​como um delimitador geral (página 12 da RFC); no entanto, se não estiver sendo usado como um delimitador geral, ambas as codificações devem resolver de forma idêntica.
Edwin Buck
Você também deve ter cuidado, pois os URLs não são realmente um subconjunto do URI: adamgent.com/post/25161273526/urls-are-not-a-subset-of-uris
Adam Gent
5

O URLEncoder Java integrado está fazendo o que deveria e você deve usá-lo.

A "+" ou "% 20" são ambos os substitutos válidos para um caractere de espaço em uma URL. Qualquer um vai funcionar.

Um ":" deve ser codificado, pois é um caractere separador. ou seja, http: // foo ou ftp: // bar . O fato de que um navegador específico pode manipulá-lo quando não está codificado não o torna correto. Você deve codificá-los.

Como uma questão de boa prática, certifique-se de usar o método que usa um parâmetro de codificação de caracteres. UTF-8 é geralmente usado lá, mas você deve fornecê-lo explicitamente.

URLEncoder.encode(yourUrl, "UTF-8");
rfeak
fonte
5
+é apenas uma representação do espaço em application/x-www-form-urlencoded; não é garantido que funcione mesmo quando restrito a HTTP. Da mesma forma, :é válido em uma string de consulta e não deve ser convertido para %3B; um servidor pode escolher interpretá-los de maneira diferente.
tc.
1
este método também codificam barras url integrais e outros personagens que fazem parte por exemplo, http://a http%3A%2F%2Fque não é correto
Para Kra
2
@ToKra você não deve codificar a http://parte. O método é para parâmetros de consulta e dados de formulário codificados. Se, no entanto, você quiser passar o URL de outro site como um parâmetro de consulta, ENTÃO você deseja codificá-lo para evitar confundir o analisador de URL.
Beldaz
@tc Minha leitura de w3.org/TR/html4/interact/forms.html#h-17.13.3.3 é que todos os dados do formulário GET são codificados como application/x-www-form-urlencodedtipo de conteúdo. Isso não significa que deve funcionar para HTTP?
beldaz
0

se você tem apenas problema de espaço na url. Eu usei o código abaixo e funcionou bem

String url;
URL myUrl = new URL(url.replace(" ","%20"));

exemplo: url é

www.xyz.com?para=hello senhor

então a saída de muUrl é

www.xyz.com?para=hello%20sir

Jignesh Patel
fonte
0
String param="2019-07-18 19:29:37";
param="%27"+param.trim().replace(" ", "%20")+"%27";

Observei no caso de Datetime (Timestamp) URLEncoder.encode(param,"UTF-8")não funcionar.

ICL Sales EXIMON
fonte