web-dev-qa-db-de.com

Analysieren von Abfragezeichenfolgen auf Android

Java EE hat ServletRequest.getParameterValues ​​() .

Auf Nicht-EE-Plattformen gibt RL.getQuery () einfach eine Zeichenfolge zurück.

Was ist die normale Methode, um die Abfragezeichenfolge in einer URL richtig zu analysieren, wenn not on Java EE?


< rant >

In den Antworten ist es beliebt, einen eigenen Parser zu erstellen. Dies ist ein sehr interessantes und aufregendes Mikrocodierungsprojekt, aber Ich kann nicht sagen, dass es eine gute Idee ist :(

Die folgenden Code-Schnipsel sind im Allgemeinen fehlerhaft oder defekt. Sie zu zerbrechen ist eine interessante Übung für den Leser. Und an die Hacker, die die Websites angreifen, die sie benutzen.

Das Analysieren von Abfragezeichenfolgen ist ein klar definiertes Problem, aber das Lesen der Spezifikation und das Verstehen der Nuancen ist nicht trivial. Es ist weitaus besser, einige Plattformbibliothekscodierer die harte Arbeit und das Reparieren für Sie erledigen zu lassen!

</rant >

266
Will

Seit Android M sind die Dinge komplizierter geworden. Die Antwort von Android.net.URI . GetQueryParameter () hat einen Fehler, der Leerzeichen vor JellyBean bricht. Apache URLEncodedUtils.parse () funktionierte, wurde aber veraltet in L und entfernt in M .

Die beste Antwort ist jetzt rlQuerySanitizer . Dies existiert seit API-Level 1 und ist immer noch vorhanden. Es lässt Sie auch über die kniffligen Fragen nachdenken, wie Sie mit Sonderzeichen oder wiederholten Werten umgehen.

Der einfachste Code ist

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
60
Nick Fortescue

Auf Android:

import Android.net.Uri;

[...]

Uri uri=Uri.parse(url_string);
uri.getQueryParameter("para1");
202
diyism
64
Will

Hier ist BalusCs Antwort , aber es kompiliert und gibt Ergebnisse zurück:

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;
}
26
dfrankow

Wenn Sie über Jetty-Bibliotheken (Server oder Client) auf Ihrem Klassenpfad verfügen, können Sie die Jetty-Util-Klassen verwenden (siehe javadoc ), z. B .:

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");
22
moritz

Wenn Sie Spring 3.1 oder höher verwenden (ich hoffe, dass die Unterstützung weiter zurückgeht), können Sie UriComponents und UriComponentsBuilder verwenden:

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

components.getQueryParams() gibt einen MultiValueMap<String, String>

Hier ist noch mehr Dokumentation .

13
Nick Spacek

Für ein Servlet oder eine JSP-Seite können Sie Schlüssel/Wert-Paare mit request.getParameter ("paramname") abfragen.

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

Es gibt andere Möglichkeiten, dies zu tun, aber so mache ich es in allen Servlets und JSP-Seiten, die ich erstelle.

5
ChadNC

Ich habe Methoden, um dies zu erreichen:

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) und der einfachste Weg dies zu tun mit ri class:

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

dies ist ein Beispiel für die Verwendung einer der beiden folgenden Methoden:

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

der Wert von tagValue ist 800

4
Jorgesys

Das Parsen der Abfragezeichenfolge ist etwas komplizierter als es scheint, je nachdem, wie verzeihend Sie sein möchten.

Erstens besteht die Abfragezeichenfolge aus ASCII-Bytes. Sie lesen diese Bytes einzeln ein und konvertieren sie in Zeichen. Ist der Charakter? oder & signalisiert dann den Beginn eines Parameternamens. Wenn das Zeichen = ist, wird der Beginn eines Parameterwerts signalisiert. Wenn das Zeichen% ist, signalisiert es den Beginn eines codierten Bytes. Hier wird es schwierig.

Wenn Sie ein% char einlesen, müssen Sie die nächsten zwei Bytes einlesen und sie als Hexadezimalziffern interpretieren. Das bedeutet, dass die nächsten zwei Bytes 0-9, a-f oder A-F sind. Kleben Sie diese beiden Hexadezimalziffern zusammen, um Ihren Bytewert zu erhalten. Aber denken Sie daran, Bytes sind keine Zeichen. Sie müssen wissen, mit welcher Codierung die Zeichen codiert wurden. Das Zeichen é codiert in UTF-8 nicht dasselbe wie in ISO-8859-1. Im Allgemeinen ist es unmöglich zu wissen, welche Codierung für einen bestimmten Zeichensatz verwendet wurde. Ich verwende immer UTF-8, weil meine Website so konfiguriert ist, dass sie immer alles mit UTF-8 bedient, aber in der Praxis können Sie sich nicht sicher sein. Einige Benutzerprogramme teilen Ihnen die Zeichenkodierung in der Anfrage mit. Sie können versuchen, dies zu lesen, wenn Sie eine vollständige HTTP-Anfrage haben. Wenn Sie nur eine einzelne URL haben, wünschen wir Ihnen viel Glück.

Angenommen, Sie verwenden UTF-8 oder eine andere Mehrbyte-Zeichencodierung. Nachdem Sie nun ein codiertes Byte decodiert haben, müssen Sie es beiseite legen, bis Sie das nächste Byte erfassen. Sie benötigen alle codierten Bytes, die zusammen gehören, da Sie nicht ein Byte gleichzeitig richtig url-decodieren können. Stellen Sie alle zusammengehörigen Bytes beiseite und dekodieren Sie sie gleichzeitig, um Ihren Charakter zu rekonstruieren.

Außerdem macht es mehr Spaß, wenn Sie nachsichtig sein und Benutzeragenten berücksichtigen möchten, die Urls entstellen. Beispielsweise codieren einige Webmail-Clients Dinge doppelt. Oder verdoppeln Sie die Zeichen? & = (Zum Beispiel: http://yoursite.com/blah??p1==v1&&p2==v2). Wenn Sie versuchen möchten, ordnungsgemäß damit umzugehen, müssen Sie Ihrem Parser mehr Logik hinzufügen.

Unter Android habe ich versucht, @diyism answer zu verwenden, bin jedoch auf das von @rpetrich hervorgerufene Problem mit Leerzeichen gestoßen. Beispiel: Ich fülle ein Formular aus, in dem username = "us+us" Und password = "pw pw" Eine URL-Zeichenfolge verursachen :

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

@Diyism-Code gibt jedoch "us+us" Und "pw+pw" Zurück, d. H. Er erkennt das Leerzeichen nicht. Wenn die URL mit %20 Umgeschrieben wurde, wird das Leerzeichen identifiziert:

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

Dies führt zu folgendem Fix:

Uri uri = Uri.parse(url_string.replace("+", "%20"));
uri.getQueryParameter("para1");
4
Stephen Quan

Am Android es ist einfach wie der Code unten:

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

Auch wenn Sie nicht jeden erwarteten Abfrageschlüssel registrieren möchten, verwenden Sie:

sanitzer.setAllowUnregisteredParamaters(true)

Vor dem Anruf:

sanitzer.parseUrl(yourUrl)
3
Kevin Crain

Das funktioniert bei mir .. Ich bin mir nicht sicher, warum jeder nach einer Map war, Liste> Alles was ich brauchte war ein einfacher Name, Wert Map.

Um die Dinge einfach zu halten, habe ich den Build in URI.getQuery () verwendet.

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
Dave

Unter Android können Sie die statische Methode Uri.parse der Klasse Android.net.Uri verwenden, um das schwere Heben durchzuführen. Wenn Sie mit URIs und Absichten arbeiten, sollten Sie sie trotzdem verwenden.

3
Patrick O'Leary

Nur zum Nachschlagen, das ist es, womit ich am Ende fertig bin (basierend auf URLEncodedUtils und der Rückgabe einer Karte).

Eigenschaften:

  • es akzeptiert den Abfragezeichenfolgeteil der URL (Sie können request.getQueryString() verwenden)
  • eine leere Abfragezeichenfolge erzeugt eine leere Map
  • ein Parameter ohne Wert (? test) wird einem leeren List<String> zugeordnet.

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

Ein Kompatibilitätshelfer (Werte werden in einem String-Array wie in ServletRequest.getParameterMap () ) gespeichert:

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;
}
3
Dan

Guavas Multimap ist dafür besser geeignet. Hier ist eine kurze übersichtliche Version:

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
pathikrit

Apache AXIS2 verfügt über eine eigenständige Implementierung von QueryStringParser.Java. Wenn Sie Axis2 nicht verwenden, laden Sie einfach den Quellcode und den Testfall von hier herunter -

http://svn.Apache.org/repos/asf/axis/axis2/Java/core/trunk/modules/kernel/src/org/Apache/axis2/transport/http/util/QueryStringParser.Java

http://svn.Apache.org/repos/asf/axis/axis2/Java/core/trunk/modules/kernel/test/org/Apache/axis2/transport/http/util/QueryStringParserTest.Java

1

Origanally beantwortet hier

Unter Android gibt es die Uri-Klasse im Paket Android.net. Beachten Sie, dass Uri Teil von Android.net ist, während URI Teil von Java.net ist.

Die Uri-Klasse hat viele Funktionen zum Extrahieren von Schlüssel-Wert-Paaren. enter image description here

Die folgende Funktion gibt Schlüssel-Wert-Paare in Form von HashMap zurück.

In Java:

Map<String, String> getQueryKeyValueMap(Uri uri){
    HashMap<String, String> keyValueMap = new HashMap();
    String key;
    String value;

    Set<String> keyNamesList = uri.getQueryParameterNames();
    Iterator iterator = keyNamesList.iterator();

    while (iterator.hasNext()){
        key = (String) iterator.next();
        value = uri.getQueryParameter(key);
        keyValueMap.put(key, value);
    }
    return keyValueMap;
}

In Kotlin:

fun getQueryKeyValueMap(uri: Uri): HashMap<String, String> {
        val keyValueMap = HashMap<String, String>()
        var key: String
        var value: String

        val keyNamesList = uri.queryParameterNames
        val iterator = keyNamesList.iterator()

        while (iterator.hasNext()) {
            key = iterator.next() as String
            value = uri.getQueryParameter(key) as String
            keyValueMap.put(key, value)
        }
        return keyValueMap
    }
0

Basierend auf der Antwort von BalusC habe ich ein Beispiel-Java-Code geschrieben:

    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
Andreas

Antworten hier, weil dies ein beliebter Thread ist. Dies ist eine saubere Lösung in Kotlin, die die empfohlene API UrlQuerySanitizer verwendet. Siehe offizielle Dokumentation . Ich habe einen String Builder hinzugefügt, um die Parameter zu verketten und anzuzeigen.

    var myURL: String? = null
    // if the url is sent from a different activity where you set it to a value
    if (intent.hasExtra("my_value")) {
        myURL = intent.extras.getString("my_value")
    } else {
        myURL = intent.dataString
    }

    val sanitizer = UrlQuerySanitizer(myURL)
    // We don't want to manually define every expected query *key*, so we set this to true
    sanitizer.allowUnregisteredParamaters = true
    val parameterNamesToValues: List<UrlQuerySanitizer.ParameterValuePair> = sanitizer.parameterList
    val parameterIterator: Iterator<UrlQuerySanitizer.ParameterValuePair> = parameterNamesToValues.iterator()

    // Helper simply so we can display all values on screen
    val stringBuilder = StringBuilder()

    while (parameterIterator.hasNext()) {
        val parameterValuePair: UrlQuerySanitizer.ParameterValuePair = parameterIterator.next()
        val parameterName: String = parameterValuePair.mParameter
        val parameterValue: String = parameterValuePair.mValue

        // Append string to display all key value pairs
        stringBuilder.append("Key: $parameterName\nValue: $parameterValue\n\n")
    }

    // Set a textView's text to display the string
    val paramListString = stringBuilder.toString()
    val textView: TextView = findViewById(R.id.activity_title) as TextView
    textView.text = "Paramlist is \n\n$paramListString"

    // to check if the url has specific keys
    if (sanitizer.hasParameter("type")) {
        val type = sanitizer.getValue("type")
        println("sanitizer has type param $type")
    }
0
jungledev
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
wafna

mit Guave:

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
Tyson

Verwenden Sie Apache HttpComponents und verbinden Sie es mit einem Sammlungscode, um auf Parameter nach Wert zuzugreifen: http://www.joelgerard.com/2012/09/14/parsing-query-strings-in-Java-and-accessing -values-by-key /

0
Joel

Ich glaube nicht, dass es einen in JRE gibt. Sie finden ähnliche Funktionen in anderen Paketen wie Apache HttpClient. Wenn Sie keine anderen Pakete verwenden, müssen Sie nur Ihre eigenen schreiben. Es ist nicht so schwer. Hier ist was ich benutze,

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
ZZ Coder