Java EE有ServletRequest.getParameterValues()。
在非ee平台上,URL.getQuery()只是返回一个字符串。
当不在Java EE上时,正确解析URL中的查询字符串的正常方法是什么?
在回答中,尝试创建自己的解析器是很受欢迎的。这是一个非常有趣和令人兴奋的微编码项目,但我不能说这是一个好主意。
下面的代码段通常是有缺陷或损坏的。对读者来说,打破它们是一项有趣的练习。还有攻击使用它们的网站的黑客。
解析查询字符串是一个明确定义的问题,但阅读规范并理解其中的细微差别并非易事。最好是让一些平台库编码器为您做艰苦的工作,并进行修复!
你说“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。)
解析查询字符串比看起来要复杂一些,这取决于您希望有多宽容。
首先,查询字符串是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)。如果您想尝试优雅地处理这个问题,就需要向解析器添加更多的逻辑。
这对我有用。
我不知道为什么每个人都想要一个地图,列表>
我所需要的只是一个简单的名称值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;
}
我认为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;
}
}
在Android上,我尝试使用@diyism回答,但我遇到了@rpetrich提出的空格字符问题,例如:
我填写了一个表单,其中用户名=“us+us”和密码=“pw pw”,导致URL字符串如下:
http://somewhere?username=us%2Bus&password=pw+pw
但是,@diyism代码返回“us+us”和“pw+pw”,即它不检测空格字符。如果URL被%20重写,空格字符将被识别:
http://somewhere?username=us%2Bus&password=pw%20pw
这导致以下修复:
Uri uri = Uri.parse(url_string.replace("+", "%20"));
uri.getQueryParameter("para1");