在Android上解析查询字符串

279

Java EE具有ServletRequest.getParameterValues()

在非EE平台上,URL.getQuery()仅返回一个字符串。

在非Java EE环境下,正确解析URL中的查询字符串的常规方法是什么?


回答中流行的方式是尝试制作自己的解析器。这是一个很有趣和激动人心的微编码项目,但我不能说这是一个好主意

下面的代码片段通常存在缺陷或错误。破解它们对读者来说是一个有趣的练习。对于攻击使用它们的网站的黑客也一样

解析查询字符串是一个已经定义明确的问题,但阅读规范并理解其细节并不容易。最好让一些平台库的开发人员为您完成艰苦的工作和修复!


1
你想从一个servlet还是JSP页面来完成这个操作?在回答之前,我需要一些澄清。 - ChadNC
我正在尝试在Android上实现这个,但所有平台上的答案都将是有用的指针(也适用于其他可能遇到这个问题的人),所以请不要犹豫! - Will
1
你还需要解析POST参数吗? - Thilo
2
即使您正在使用J2EE(或通过OSGi添加了选定的EE包,如我所做),这个问题也可能是有意义的。在我的情况下,查询字符串/ URL编码的POST正文由系统的一部分处理,该部分故意忽略诸如ServletRequest之类的东西。 - Hanno Fietz
@Will 我不知道你是否已经解决了你的问题,但是这个库 http://cxf.apache.org/docs/jax-rs-advanced-features.html 对我很有帮助!看一下,还支持FIQL。 - rafa.ferreira
显示剩余2条评论
25个回答

0

我认为JRE中没有这样的功能。您可以在其他软件包(如Apache HttpClient)中找到类似的函数。如果您不使用其他软件包,您只需编写自己的函数即可。这并不难。以下是我使用的代码示例:

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

使用 Apache 类有哪些方法? - Will
1
您可以使用parse()方法:http://hc.apache.org/httpcomponents-client/httpclient/apidocs/org/apache/http/client/utils/URLEncodedUtils.html - ZZ Coder
3
请将Apache Commons的链接放在独立的答案中,这样我才能投票支持它。 - itsadok

0

使用 Guava:

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

-2

此方法接受 URI,并返回参数名称和参数值的映射表。

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

1
根据我之前的抱怨,这个问题可以很容易地导致崩溃。不要费力修复,直接使用专业的实用库即可。 - Will

-4

你说“Java”,但不是“Java EE”。你的意思是你正在使用JSP和/或servlet,但不是完整的Java EE堆栈吗?如果是这样,那么您仍然应该可以使用request.getParameter()。

如果你的意思是你正在编写Java,但你不是在编写JSP或servlet,或者你只是把Java作为你的参考点,但你在一些其他平台上,没有内置的参数解析...哇,这听起来像一个不太可能的问题,但如果是这样,原则将是:

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

我可以写Java代码,但这是没有意义的,因为如果您有Java可用,您可以直接使用request.getParameters。


在解码十六进制数字时,要注意字符编码。 - Mr. Shiny and New 安宇
这是Android,因此使用Java而不是J2EE。 - Andrzej Doyle
我忘了提到:您还需要检查“+”,它应该被翻译为空格。嵌入式空格在查询字符串中是不合法的。 - Jay

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接