Analyse des chaînes de requête sur Android

Java EE a ServletRequest.getParameterValues () .

Sur la non-EE plates-formes, de l'URL.getQuery () renvoie simplement une chaîne.

Quelle est la façon normale de bien analyser la chaîne de requête dans une URL lorsque n'est pas sur Java EE?


< coup de gueule >

Il est populaire dans les réponses à essayer et faire votre propre analyseur. C'est très intéressant et passionnant projet de micro-codage, mais Je ne peux pas dire que c'est une bonne idée :(

les morceaux de code ci-dessous sont généralement défectueux ou cassés, btw. La rupture est un exercice intéressant pour le lecteur. et aux pirates qui attaquent les sites Web qui les utilisent .

analyser les chaînes de requête est un problème bien défini, mais lire les spécifications et comprendre les nuances n'est pas anodin. Il est de loin préférable de laisser un codeur de bibliothèque de plate-forme faire le travail difficile, et faire la réparation, pour vous!

< /coup de gueule >

251
demandé sur rds 2009-11-03 16:15:24
la source

23 ответов

depuis Android M les choses sont devenues plus compliquées. La réponse de android.net.URI .getQueryParameter () a un bug qui casse les espaces avant JellyBean. Apache URLEncodedUtils.parse() a travaillé, mais a été obsolète dans L , et retiré en M .

donc la meilleure réponse maintenant est UrlQuerySanitizer . Cela existe depuis le niveau 1 de L'API et exister. Il vous fait également penser aux questions délicates comme la façon dont vous manipulez des caractères spéciaux, ou des valeurs répétées.

le code le plus simple est

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
55
répondu Nick Fortescue 2016-04-20 11:24:48
la source

Sur Android:

import android.net.Uri;

[...]

Uri uri=Uri.parse(url_string);
uri.getQueryParameter("para1");
198
répondu diyism 2015-06-26 23:01:24
la source

Voici réponse de BalusC , mais il compile et renvoie des résultats:

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;
}
25
répondu dfrankow 2017-05-23 15:10:26
la source

si vous avez des libs de jetty (serveur ou client) sur votre chemin de classe, vous pouvez utiliser les classes util de jetty (voir javadoc ), par exemple:

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");
21
répondu moritz 2011-03-18 20:46:33
la source

si vous utilisez Spring 3.1 ou plus (yikes, espérait que le support est allé plus loin), vous pouvez utiliser le UriComponents et UriComponentsBuilder :

UriComponents components = UriComponentsBuilder.fromUri(uri).build();
List<String> myParam = components.getQueryParams().get("myParam");

components.getQueryParams() retourne un MultiValueMap<String, String>

voici plus de documentation .

13
répondu Nick Spacek 2013-07-09 14:43:54
la source

pour un servlet ou une page JSP, vous pouvez obtenir des paires clé/valeur de querystring en utilisant request.getParameter ("paramname")

String name = request.getParameter("name");

il y a d'autres façons de le faire, mais c'est la façon dont je le fais dans toutes les pages servlets et jsp que je crée.

6
répondu ChadNC 2009-11-03 16:50:10
la source

analyser la chaîne de requête est un peu plus compliqué qu'il n'y paraît, en fonction du degré de pardon que vous voulez être.

tout d'abord, la chaîne de requête est des octets ascii. Vous lisez dans ces octets un à la fois et les convertissez en caractères. Si le personnage est ? ou et puis il indique le début d'un nom de paramètre. Si le caractère est = alors il signale le début d'une valeur paramétrique. Si le caractère est: % puis il indique le début d'un octet codé. C'est ce qui est délicat.

quand vous lisez dans un % char vous devez lire les deux octets suivants et les interpréter comme des chiffres hexadécimaux. Cela signifie que les deux prochains octets seront 0-9, A-f ou A-F. collez ces deux chiffres hexadécimaux ensemble pour obtenir votre valeur de byte. Mais rappelez-vous, bytes ne sont pas des caractères . Vous devez savoir quel encodage a été utilisé pour encoder les caractères. Le caractère é n'est pas codé de la même façon dans UTF-8 que dans ISO-8859-1. En général, il est impossible de savoir ce qu' le codage a été utilisé pour un jeu de caractères donné. J'utilise toujours UTF-8 parce que mon site web est configuré pour toujours servir tout en utilisant UTF-8 mais dans la pratique, vous ne pouvez pas être certain. Certains agents utilisateurs vous indiqueront l'encodage des caractères dans la requête; vous pouvez essayer de le lire si vous avez une requête HTTP complète. Si vous avez juste une url en isolation, bonne chance.

de toute façon, en supposant que vous utilisez UTF-8 ou un autre encodage de caractères multi-octets, maintenant que vous avez décodé un encodé byte vous devez le mettre de côté jusqu'à ce que vous capturez le prochain byte. Vous avez besoin de tous les octets codés qui sont ensemble parce que vous ne pouvez pas url-decode correctement un octet à la fois. Mettez de côté tous les octets qui sont ensemble puis décodez-les tous à la fois pour reconstruire votre caractère.

Plus il obtient plus de plaisir si vous voulez être indulgent et de rendre compte pour les agents-utilisateurs qui mandlent des urls. Par exemple, certains clients webmail double-encodent des choses. Ou le double de l' ?&= caractères (par exemple: http://yoursite.com/blah??p1==v1&&p2==v2 ). Si vous voulez essayer pour normalement faire face à cela, vous aurez besoin d'ajouter plus logique de votre analyseur.

4
répondu Mr. Shiny and New 安宇 2009-11-03 17:47:17
la source

juste pour référence, c'est ce que j'ai fini avec (basé sur URLEncodedUtils, et en retournant une carte).

Dispose:

  • il accepte la partie de la chaîne de requête de l'url (vous pouvez utiliser request.getQueryString() )
  • une chaîne de requête vide produira une chaîne vide Map
  • paramètre sans valeur (?test) sera mappé à un vide List<String>

Code:

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 helper de compatibilité (les valeurs sont stockées dans un tableau de chaînes de caractères comme dans 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;
}
4
répondu Dan 2011-06-28 13:30:40
la source

sur Android, j'ai essayé d'utiliser la réponse de @diyism mais j'ai rencontré le problème de caractère d'espace soulevé par @rpetrich, par exemple: Je remplis un formulaire où username = "us+us" et password = "pw pw" faisant ressembler une chaîne D'URL à:

http://somewhere?username=us%2Bus&password=pw+pw

cependant, le code @diyism renvoie "us+us" et "pw+pw" , c'est-à-dire qu'il ne détecte pas le caractère d'espace. Si L'URL a été réécrite avec %20 le caractère d'espace est identifié:

http://somewhere?username=us%2Bus&password=pw%20pw

Cela conduit à la correction suivante:

Uri uri = Uri.parse(url_string.replace("+", "%20"));
uri.getQueryParameter("para1");
4
répondu Stephen Quan 2012-11-29 02:51:16
la source

j'ai des méthodes pour y arriver:

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) et la manière la plus facile de le faire en utilisant Uri classe:

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 "";
}

et c'est un exemple de comment utiliser une des deux méthodes:

String url = "http://www.jorgesys.com/advertisements/publicidadmobile.htm?position=x46&site=reform&awidth=800&aheight=120";      
String tagValue = getQueryString(url,"awidth");

la valeur de tagValue est 800

4
répondu Jorgesys 2018-04-17 18:01:45
la source

ça me va.. Je ne suis pas sûr pourquoi tout le monde était après une carte, Liste> Tout ce dont j'avais besoin, c'était d'une simple carte des valeurs des noms.

pour simplifier les choses, J'ai utilisé le build in 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;
}
3
répondu Dave 2012-02-12 17:29:39
la source

sur Android son simple comme le code ci-dessous:

UrlQuerySanitizer sanitzer = new UrlQuerySanitizer(url);
String value = sanitzer.getValue("your_get_parameter");

également si vous ne voulez pas enregistrer chaque requête attendue utilisation de la clé:

sanitzer.setAllowUnregisteredParamaters(true)

avant d'appeler:

sanitzer.parseUrl(yourUrl)
3
répondu Kevin Crain 2016-10-25 14:45:37
la source

sur Android, vous pouvez utiliser L'Uri.analyse méthode statique du android.net.Uri classe pour faire le levage lourd. Si vous faites quelque chose avec des URIs et des intentions, vous voudrez l'utiliser de toute façon.

2
répondu Patrick O'Leary 2010-03-10 02:45:38
la source

le Multimap de la goyave est mieux adapté pour cela. Voici une version courte et nette:

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);
        }
    }
2
répondu pathikrit 2012-03-19 20:29:32
la source

Je ne pense pas qu'il y en ait un dans JRE. Vous pouvez trouver des fonctions similaires dans D'autres paquets comme Apache HttpClient. Si vous n'utilisez pas d'autres paquets, il vous suffit d'écrire votre propre. Il n'est pas difficile. Voici ce que j'utilise,

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;
 } 
}
0
répondu ZZ Coder 2009-11-03 19:42:45
la source

basé sur la réponse de BalusC, j'ai écrit quelque exemple-Java-Code:

    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
            }
        }
    }
0
répondu Andreas 2010-03-01 15:33:20
la source
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;
}
0
répondu wafna 2011-02-23 19:27:56
la source

utilisez Apache HttpComponents et connectez-le avec un code de collecte pour accéder aux paramètres en valeur: http://www.joelgerard.com/2012/09/14/parsing-query-strings-in-java-and-accessing-values-by-key/

0
répondu Joel 2012-09-15 02:04:35
la source

utilisant la goyave:

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;
}
0
répondu Tyson 2013-05-20 18:38:39
la source

cette méthode prend l'uri et la carte de retour du nom Au Pair et de la valeur au pair

  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;
}
-2
répondu FAHAD HAMMAD ALOTAIBI 2015-04-14 17:31:15
la source

vous dites "Java" mais "pas Java EE". Voulez-vous dire que vous utilisez JSP et/ou servlets mais pas une pile Java EE complète? Si c'est le cas, alors vous devriez avoir une demande.getParameter () est à votre disposition.

si vous voulez dire que vous écrivez Java, mais que vous n'écrivez ni JSPs ni servlets, ou que vous utilisez simplement Java comme point de référence, mais que vous êtes sur une autre plate-forme qui n'a pas de parsing intégré des paramètres ... Wow, ça ressemble juste à un improbable question, mais si oui, le principe serait:

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

(je pourrais écrire du code Java mais ce serait inutile, parce que si vous avez Java disponible, vous pouvez simplement utiliser request.getParameters.)

-3
répondu Jay 2012-07-10 21:54:59
la source

Autres questions sur java android url parsing