Java EE有ServletRequest.getParameterValues()。
在非ee平台上,URL.getQuery()只是返回一个字符串。
当不在Java EE上时,正确解析URL中的查询字符串的正常方法是什么?
在回答中,尝试创建自己的解析器是很受欢迎的。这是一个非常有趣和令人兴奋的微编码项目,但我不能说这是一个好主意。
下面的代码段通常是有缺陷或损坏的。对读者来说,打破它们是一项有趣的练习。还有攻击使用它们的网站的黑客。
解析查询字符串是一个明确定义的问题,但阅读规范并理解其中的细微差别并非易事。最好是让一些平台库编码器为您做艰苦的工作,并进行修复!
解析查询字符串比看起来要复杂一些,这取决于您希望有多宽容。
首先,查询字符串是ascii字节。每次读入一个字节,然后将它们转换成字符。如果角色是?或者&,然后它表示参数名的开始。如果字符为=,则它表示一个参数值的开始。如果字符为%,则表示已编码字节的开始。这就是棘手的地方。
When you read in a % char you have to read the next two bytes and interpret them as hex digits. That means the next two bytes will be 0-9, a-f or A-F. Glue these two hex digits together to get your byte value. But remember, bytes are not characters. You have to know what encoding was used to encode the characters. The character é does not encode the same in UTF-8 as it does in ISO-8859-1. In general it's impossible to know what encoding was used for a given character set. I always use UTF-8 because my web site is configured to always serve everything using UTF-8 but in practice you can't be certain. Some user-agents will tell you the character encoding in the request; you can try to read that if you have a full HTTP request. If you just have a url in isolation, good luck.
不管怎样,假设您正在使用UTF-8或其他一些多字节字符编码,现在您已经解码了一个已编码的字节,您必须将其放在一边,直到捕获下一个字节。您需要所有已编码的字节放在一起,因为您不能一次正确地对一个字节进行url解码。把所有在一起的字节放在一边,然后立刻解码,重新构建你的角色。
另外,如果你想要宽容一些,并解释用户代理破坏url,它会变得更有趣。例如,一些webmail客户端会对内容进行双重编码。或者使用两个?&=字符(例如:http://yoursite.com/blah??p1==v1&&p2==v2)。如果您想尝试优雅地处理这个问题,就需要向解析器添加更多的逻辑。
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("=", 2);
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;
}
使用番石榴:
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;
}