java - http_ok - setrequestproperty android
Análisis de cadenas de consulta en Android (24)
Java EE tiene ServletRequest.getParameterValues() .
En plataformas que no son de EE, URL.getQuery() simplemente devuelve una cadena.
¿Cuál es la forma normal de analizar correctamente la cadena de consulta en una URL cuando no está en Java EE?
< rant >
Es popular en las respuestas tratar de hacer tu propio analizador. Este es un proyecto de microcodificación muy interesante y emocionante, pero no puedo decir que sea una buena idea :(
Los fragmentos de código a continuación son generalmente defectuosos o rotos, por cierto. Romperlos es un ejercicio interesante para el lector. Y a los hackers que atacan los sitios web que los utilizan .
Analizar cadenas de consulta es un problema bien definido, pero leer las especificaciones y comprender los matices no es trivial. ¡Es mucho mejor dejar que algunos programadores de bibliotecas de plataformas hagan el trabajo duro y hagan los arreglos, por usted!
< / rant >
Analizar la cadena de consulta es un poco más complicado de lo que parece, dependiendo de qué tan indiferente quiera ser.
Primero, la cadena de consulta es ascii bytes. Usted lee estos bytes uno a la vez y los convierte en caracteres. Si el personaje es? o y luego señala el inicio de un nombre de parámetro. Si el carácter es =, entonces señala el inicio de un valor de parámetro. Si el carácter es%, entonces señala el inicio de un byte codificado. Aquí es donde se pone difícil.
Cuando lees en% char tienes que leer los siguientes dos bytes e interpretarlos como dígitos hexadecimales. Eso significa que los siguientes dos bytes serán 0-9, af o AF. Pegue estos dos dígitos hexadecimales para obtener su valor de byte. Pero recuerda, los bytes no son caracteres . Tienes que saber qué codificación se utilizó para codificar los caracteres. El carácter é no codifica lo mismo en UTF-8 como lo hace en ISO-8859-1. En general, es imposible saber qué codificación se utilizó para un conjunto de caracteres determinado. Siempre uso UTF-8 porque mi sitio web está configurado para servir siempre todo usando UTF-8, pero en la práctica no puede estar seguro. Algunos agentes de usuario le dirán la codificación de caracteres en la solicitud; Puedes intentar leer eso si tienes una solicitud HTTP completa. Si solo tienes una url aislada, buena suerte.
De todos modos, suponiendo que esté utilizando UTF-8 o alguna otra codificación de caracteres de múltiples bytes, ahora que ha descodificado un byte codificado, debe dejarlo de lado hasta que capture el siguiente byte. Necesita todos los bytes codificados que están juntos porque no puede decodificar url correctamente un byte a la vez. Ponga a un lado todos los bytes que están juntos y luego decodifíquelos todos a la vez para reconstruir su personaje.
Además, se vuelve más divertido si quieres ser indulgente y tener en cuenta a los agentes de usuario que manejan las URL. Por ejemplo, algunos clientes de correo web codifican dos veces. O doble los caracteres? & = (Por ejemplo: http://yoursite.com/blah??p1==v1&&p2==v2
). Si desea tratar de resolver esto con gracia, deberá agregar más lógica a su analizador.
Apache AXIS2 tiene una implementación independiente de QueryStringParser.java. Si no está utilizando Axis2, simplemente descargue el código fuente y el caso de prueba desde aquí.
Aquí está la respuesta de BalusC , pero compila y devuelve resultados:
public static Map<String, List<String>> getUrlParameters(String url)
throws UnsupportedEncodingException {
Map<String, List<String>> params = new HashMap<String, List<String>>();
String[] urlParts = url.split("//?");
if (urlParts.length > 1) {
String query = urlParts[1];
for (String param : query.split("&")) {
String pair[] = param.split("=");
String key = URLDecoder.decode(pair[0], "UTF-8");
String value = "";
if (pair.length > 1) {
value = URLDecoder.decode(pair[1], "UTF-8");
}
List<String> values = params.get(key);
if (values == null) {
values = new ArrayList<String>();
params.put(key, values);
}
values.add(value);
}
}
return params;
}
Basándome en la respuesta de BalusC, escribí un ejemplo de código Java:
if (queryString != null)
{
final String[] arrParameters = queryString.split("&");
for (final String tempParameterString : arrParameters)
{
final String[] arrTempParameter = tempParameterString.split("=");
if (arrTempParameter.length >= 2)
{
final String parameterKey = arrTempParameter[0];
final String parameterValue = arrTempParameter[1];
//do something with the parameters
}
}
}
Desde Android M las cosas se han vuelto más complicadas. La respuesta de android.net.URI .getQueryParameter () tiene un error que rompe espacios antes de JellyBean. Apache URLEncodedUtils.parse () funcionó, pero fue desaprobado en L y eliminado en M.
Así que la mejor respuesta ahora es UrlQuerySanitizer . Esto ha existido desde el nivel 1 de API y todavía existe. También te hace pensar en problemas difíciles, como cómo manejar caracteres especiales o valores repetidos.
El código más simple es
UrlQuerySanitizer.ValueSanitizer sanitizer = UrlQuerySanitizer.getAllButNullLegal();
// remember to decide if you want the first or last parameter with the same name
// If you want the first call setPreferFirstRepeatedParameter(true);
sanitizer.parseUrl(url);
String value = sanitizer.getValue("paramname"); // get your value
Dices "Java" pero "no Java EE". ¿Quiere decir que está utilizando JSP y / o servlets pero no una pila completa de Java EE? Si ese es el caso, entonces debería tener request.getParameter () disponible para usted.
Si quiere decir que está escribiendo Java pero no está escribiendo JSP ni servlets, o simplemente está usando Java como su punto de referencia pero está en alguna otra plataforma que no tiene un análisis de parámetros incorporado ... Wow , eso suena como una pregunta poco probable, pero si es así, el principio sería:
xparm=0 word="" loop get next char if no char exit loop if char==''='' param_name[xparm]=word word="" else if char==''&'' param_value[xparm]=word word="" xparm=xparm+1 else if char==''%'' read next two chars word=word+interpret the chars as hex digits to make a byte else word=word+char
(Podría escribir código Java, pero no tendría sentido, porque si tiene Java disponible, solo puede usar request.getParameters).
El Multimap de Guava es más adecuado para esto. Aquí hay una versión corta y limpia:
Multimap<String, String> getUrlParameters(String url) {
try {
Multimap<String, String> ret = ArrayListMultimap.create();
for (NameValuePair param : URLEncodedUtils.parse(new URI(url), "UTF-8")) {
ret.put(param.getName(), param.getValue());
}
return ret;
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
}
En Android es tan simple como el siguiente código:
UrlQuerySanitizer sanitzer = new UrlQuerySanitizer(url);
String value = sanitzer.getValue("your_get_parameter");
Además, si no desea registrar cada clave de consulta esperada, utilice:
sanitzer.setAllowUnregisteredParamaters(true)
Antes de llamar:
sanitzer.parseUrl(yourUrl)
En Android, intenté usar la respuesta de @diyism, pero encontré el problema del carácter de espacio provocado por @rpetrich, por ejemplo: Relleno un formulario donde username = "us+us"
y password = "pw pw"
causando que se vea una cadena de URL me gusta:
http://somewhere?username=us%2Bus&password=pw+pw
Sin embargo, el código @diyism devuelve "us+us"
y "pw+pw"
, es decir, no detecta el carácter de espacio. Si la URL se reescribió con %20
, se identifica el carácter de espacio:
http://somewhere?username=us%2Bus&password=pw%20pw
Esto conduce a la siguiente solución:
Uri uri = Uri.parse(url_string.replace("+", "%20"));
uri.getQueryParameter("para1");
En Android, las bibliotecas de Apache proporcionan un analizador de consultas:
http://developer.android.com/reference/org/apache/http/client/utils/URLEncodedUtils.html y http://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/org/apache/http/client/utils/URLEncodedUtils.html
En Android, puedes usar el método estático Uri.parse de la clase android.net.Uri para hacer el trabajo pesado. Si estás haciendo algo con URIs e Intents querrás usarlo de todas formas.
En Android:
import android.net.Uri;
[...]
Uri uri=Uri.parse(url_string);
uri.getQueryParameter("para1");
Esto me funciona ... No estoy seguro de por qué cada uno estaba después de un Mapa, Lista> Todo lo que necesitaba era un Mapa de valor de nombre simple.
Para mantener las cosas simples, utilicé la compilación en URI.getQuery ();
public static Map<String, String> getUrlParameters(URI uri)
throws UnsupportedEncodingException {
Map<String, String> params = new HashMap<String, String>();
for (String param : uri.getQuery().split("&")) {
String pair[] = param.split("=");
String key = URLDecoder.decode(pair[0], "UTF-8");
String value = "";
if (pair.length > 1) {
value = URLDecoder.decode(pair[1], "UTF-8");
}
params.put(new String(key), new String(value));
}
return params;
}
No creo que haya uno en JRE. Puede encontrar funciones similares en otros paquetes como Apache HttpClient. Si no usa ningún otro paquete, solo tiene que escribir el suyo. No es tan dificil. Aquí está lo que yo uso,
public class QueryString {
private Map<String, List<String>> parameters;
public QueryString(String qs) {
parameters = new TreeMap<String, List<String>>();
// Parse query string
String pairs[] = qs.split("&");
for (String pair : pairs) {
String name;
String value;
int pos = pair.indexOf(''='');
// for "n=", the value is "", for "n", the value is null
if (pos == -1) {
name = pair;
value = null;
} else {
try {
name = URLDecoder.decode(pair.substring(0, pos), "UTF-8");
value = URLDecoder.decode(pair.substring(pos+1, pair.length()), "UTF-8");
} catch (UnsupportedEncodingException e) {
// Not really possible, throw unchecked
throw new IllegalStateException("No UTF-8");
}
}
List<String> list = parameters.get(name);
if (list == null) {
list = new ArrayList<String>();
parameters.put(name, list);
}
list.add(value);
}
}
public String getParameter(String name) {
List<String> values = parameters.get(name);
if (values == null)
return null;
if (values.size() == 0)
return "";
return values.get(0);
}
public String[] getParameterValues(String name) {
List<String> values = parameters.get(name);
if (values == null)
return null;
return (String[])values.toArray(new String[values.size()]);
}
public Enumeration<String> getParameterNames() {
return Collections.enumeration(parameters.keySet());
}
public Map<String, String[]> getParameterMap() {
Map<String, String[]> map = new TreeMap<String, String[]>();
for (Map.Entry<String, List<String>> entry : parameters.entrySet()) {
List<String> list = entry.getValue();
String[] values;
if (list == null)
values = null;
else
values = (String[]) list.toArray(new String[list.size()]);
map.put(entry.getKey(), values);
}
return map;
}
}
Para un servlet o una página JSP, puede obtener pares de clave / valor de cadena de consulta utilizando request.getParameter ("paramname")
String name = request.getParameter("name");
Existen otras formas de hacerlo, pero así lo hago en todos los servlets y páginas jsp que creo.
Respondiendo aquí porque este es un hilo popular. Esta es una solución limpia en Kotlin que utiliza la API UrlQuerySanitizer
recomendada. Consulte la documentación oficial . He añadido un generador de cadenas para concatenar y mostrar los parámetros.
public static Map<String, String> getQueryMap(String uri) {
String queryParms[] = uri.split("//?");
Map<String, String> map = new HashMap<>();//
if (queryParms == null || queryParms.length == 0) return map;
String[] params = queryParms[1].split("&");
for (String param : params) {
String name = param.split("=")[0];
String value = param.split("=")[1];
map.put(name, value);
}
return map;
}
Si está utilizando Spring 3.1 o superior (sí, esperaba que el soporte volviera a UriComponents
), puede usar UriComponents
y UriComponentsBuilder
:
UriComponents components = UriComponentsBuilder.fromUri(uri).build();
List<String> myParam = components.getQueryParams().get("myParam");
components.getQueryParams()
devuelve un MultiValueMap<String, String>
Si tiene librerías de embarcadero (servidor o cliente) en su ruta de clase, puede usar las clases de utilería de embarcadero (ver javadoc ), por ejemplo:
import org.eclipse.jetty.util.*;
URL url = new URL("www.example.com/index.php?foo=bar&bla=blub");
MultiMap<String> params = new MultiMap<String>();
UrlEncoded.decodeTo(url.getQuery(), params, "UTF-8");
assert params.getString("foo").equals("bar");
assert params.getString("bla").equals("blub");
Solo como referencia, esto es con lo que terminé (basado en URLEncodedUtils y devolviendo un Mapa).
caracteristicas:
- acepta la parte de la cadena de consulta de la url (puede usar
request.getQueryString()
) - una cadena de consulta vacía producirá un
Map
vacío - un parámetro sin un valor (? prueba) se asignará a una
List<String>
vacíaList<String>
Código:
public static Map<String, List<String>> getParameterMapOfLists(String queryString) {
Map<String, List<String>> mapOfLists = new HashMap<String, List<String>>();
if (queryString == null || queryString.length() == 0) {
return mapOfLists;
}
List<NameValuePair> list = URLEncodedUtils.parse(URI.create("http://localhost/?" + queryString), "UTF-8");
for (NameValuePair pair : list) {
List<String> values = mapOfLists.get(pair.getName());
if (values == null) {
values = new ArrayList<String>();
mapOfLists.put(pair.getName(), values);
}
if (pair.getValue() != null) {
values.add(pair.getValue());
}
}
return mapOfLists;
}
Un ayudante de compatibilidad (los valores se almacenan en una matriz de cadenas como en ServletRequest.getParameterMap() ):
public static Map<String, String[]> getParameterMap(String queryString) {
Map<String, List<String>> mapOfLists = getParameterMapOfLists(queryString);
Map<String, String[]> mapOfArrays = new HashMap<String, String[]>();
for (String key : mapOfLists.keySet()) {
mapOfArrays.put(key, mapOfLists.get(key).toArray(new String[] {}));
}
return mapOfArrays;
}
Tengo métodos para lograr esto:
1) :
public static String getQueryString(String url, String tag) {
String[] params = url.split("&");
Map<String, String> map = new HashMap<String, String>();
for (String param : params) {
String name = param.split("=")[0];
String value = param.split("=")[1];
map.put(name, value);
}
Set<String> keys = map.keySet();
for (String key : keys) {
if(key.equals(tag)){
return map.get(key);
}
System.out.println("Name=" + key);
System.out.println("Value=" + map.get(key));
}
return "";
}
2) y la forma más fácil de hacerlo usando la clase Uri :
public static String getQueryString(String url, String tag) {
try {
Uri uri=Uri.parse(url);
return uri.getQueryParameter(tag);
}catch(Exception e){
Log.e(TAG,"getQueryString() " + e.getMessage());
}
return "";
}
y este es un ejemplo de cómo usar uno de los dos métodos:
String url = "http://www.jorgesys.com/advertisements/publicidadmobile.htm?position=x46&site=reform&awidth=800&aheight=120";
String tagValue = getQueryString(url,"awidth");
el valor de tagValue es 800
Use Apache HttpComponents y conéctelo con algún código de colección para acceder a params por valor: http://www.joelgerard.com/2012/09/14/parsing-query-strings-in-java-and-accessing-values-by-key/
este método toma el uri y el mapa de retorno de nombre par y valor par
xparm=0
word=""
loop
get next char
if no char
exit loop
if char==''=''
param_name[xparm]=word
word=""
else if char==''&''
param_value[xparm]=word
word=""
xparm=xparm+1
else if char==''%''
read next two chars
word=word+interpret the chars as hex digits to make a byte
else
word=word+char
utilizando guayaba:
Multimap<String,String> parseQueryString(String queryString, String encoding) {
LinkedListMultimap<String, String> result = LinkedListMultimap.create();
for(String entry : Splitter.on("&").omitEmptyStrings().split(queryString)) {
String pair [] = entry.split("=", 2);
try {
result.put(URLDecoder.decode(pair[0], encoding), pair.length == 2 ? URLDecoder.decode(pair[1], encoding) : null);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
return result;
}
public static Map <String, String> parseQueryString (final URL url)
throws UnsupportedEncodingException
{
final Map <String, String> qps = new TreeMap <String, String> ();
final StringTokenizer pairs = new StringTokenizer (url.getQuery (), "&");
while (pairs.hasMoreTokens ())
{
final String pair = pairs.nextToken ();
final StringTokenizer parts = new StringTokenizer (pair, "=");
final String name = URLDecoder.decode (parts.nextToken (), "ISO-8859-1");
final String value = URLDecoder.decode (parts.nextToken (), "ISO-8859-1");
qps.put (name, value);
}
return qps;
}