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)。如果您想尝试优雅地处理这个问题,就需要向解析器添加更多的逻辑。
仅供参考,这是我最终得到的结果(基于URLEncodedUtils,并返回一个Map)。
特点:
它接受url的查询字符串部分(你可以使用request.getQueryString())
空查询字符串将产生空Map
没有值的参数(?test)将被映射为空List<String>
代码:
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;
}
兼容性帮助器(值存储在String数组中,就像在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;
}
这对我有用。
我不知道为什么每个人都想要一个地图,列表>
我所需要的只是一个简单的名称值Map。
为了简单起见,我使用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;
}