在 Java 中解码 URI 查询字符串
Posted
技术标签:
【中文标题】在 Java 中解码 URI 查询字符串【英文标题】:Decoding URI query string in Java 【发布时间】:2011-02-07 14:21:40 【问题描述】:我需要解码一个包含查询字符串的 URI;预期的输入/输出行为类似于以下内容:
abstract class URIParser
/** example input:
* something?alias=pos&FirstName=Foo+A%26B%3DC&LastName=Bar */
URIParser(String input) ...
/** should return "something" for the example input */
public String getPath();
/** should return a map
* alias: "pos", FirstName: "Foo+A&B=C", LastName: "Bar" */
public Map<String,String> getQuery();
我尝试过使用java.net.URI,但它似乎可以解码查询字符串,所以在上面的示例中,我留下了“alias=pos&FirstName=Foo+A&B=C&LastName=Bar”,因此“是否”存在歧义&" 是查询分隔符或查询组件中的字符。
编辑:我刚刚尝试了URI.getRawQuery(),但它没有进行编码,所以我可以用&
拆分查询字符串,但是我该怎么办? javascript有decodeURIComponent,Java中好像找不到对应的方法。
有什么建议吗?我不想使用任何新的库。
【问题讨论】:
既然你不想引入新的库,请问你是在什么环境下收到这些URI的? 【参考方案1】:使用
URLDecoder.decode(proxyRequestParam.replace("+", "%2B"), "UTF-8")
.replace("%2B", "+")
模拟decodeURIComponent
。 Java 的URLDecoder
将加号解码为空格,这不是您想要的,因此您需要替换语句。
警告:末尾的
.replace("%2B", "+")
会损坏您的数据如果原始数据(pre-x-www-form-urlencoded ) 包含该字符串,正如@xehpuk 指出的那样。
【讨论】:
这应该是公认的答案。 URI 按原样处理 + 符号,而空格被编码为 %20。 URLDecoder 与 URI 编码字符串不兼容,因为它会将 + 和 %20 解码为空格。 第二次替换有什么意义?解码后,字符串中将不再有任何“%2B”实例,因为它们都将被替换为“+”,因此替换将没有任何内容。 重点是您不希望在解码字符串中包含编码字符。由于 Java 不会像 JavaScript 那样解码 + 符号,因此我首先对 + 符号进行编码,这样它就不会被 Java 触及,然后将 %2B 解码为 + 符号。简而言之:如果我不这样做,解码后的 URL 将不包含原始的 + 符号(因为 Java 在解码阶段会丢失它们)。 @janb - 我认为第二次替换是不必要的,因为decode
方法已经将它找到的任何%2B
转换为+
。第一次替换是必要的,以阻止它将+
转换为空格。
@StevePowell 第二次替换不仅没有必要,而且是错误的。【参考方案2】:
见课程URLDecoder
【讨论】:
应该注意的是,您应该在使用它之前识别查询部分并将参数拆分为键/值对,但它会将百分比编码的值解码为给定的编码(参见 UTF- 8) 根据 htmlapplication/x-www-form-urlencoded
规范。
总是把答案放在你的答案中。链接会产生额外的工作,并且不能保证链接将始终有效。【参考方案3】:
var reqParam = URLDecoder.decode(reqParam, "UTF-8")
【讨论】:
【参考方案4】:关于 + 号的问题:
我根据@janb 的回答做了一个封装了 URLDecoder 函数的辅助类
import android.net.Uri;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
public class DateDecoder
private static final String KEY_DATE = "datekey";
private static final SimpleDateFormat SIMPLE_DATE_FORMAT =
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZZZZZ", Locale.US);
public static void main(String[] args) throws UnsupportedEncodingException
try
Uri uri = Uri.parse("http://asdf.com?something=12345&" +
KEY_DATE +"=2016-12-24T12:00:00+01:00");
System.out.println("parsed date: " + DateDecoder.createDate(uri)); // parsed date: Sat Dec 24 12:00:00 GMT+01:00 2016
catch (Exception e)
e.printStackTrace();
@Nullable
public static Date createDate(@Nullable Uri data)
if (data != null)
try
String withPlus = decodeButKeepPlus(KEY_DATE, data.getEncodedQuery());
if (!TextUtils.isEmpty(withPlus))
return SIMPLE_DATE_FORMAT.parse(withPlus);
catch (Exception e)
e.printStackTrace();
return null;
/**
* copied from android.net.Uri.java
*/
@Nullable
public static String decodeButKeepPlus(String encodedKey, String completeEncodedQuery)
throws UnsupportedEncodingException
final int length = completeEncodedQuery.length();
int start = 0;
do
int nextAmpersand = completeEncodedQuery.indexOf('&', start);
int end = nextAmpersand != -1 ? nextAmpersand : length;
int separator = completeEncodedQuery.indexOf('=', start);
if (separator > end || separator == -1)
separator = end;
if (separator - start == encodedKey.length()
&& completeEncodedQuery.regionMatches(start, encodedKey, 0, encodedKey.length()))
if (separator == end)
return "";
else
String encodedValue = completeEncodedQuery.substring(separator + 1, end);
if (!TextUtils.isEmpty(encodedValue))
return URLDecoder.decode(encodedValue.replace("+", "%2B"), "UTF-8").replace("%2B", "+");
// Move start to end of name.
if (nextAmpersand != -1)
start = nextAmpersand + 1;
else
break;
while (true);
return null;
【讨论】:
【参考方案5】:new java.net.URI(proxyRequestParam).getPath()
js encodeURIComponent编码的字符串应该只是一个路径,没有schema等。但是它仍然是 java.net.URI 的有效输入。所以 java.net.URI 会为我们做所有事情,然后它的路径就是我们想要的。
【讨论】:
虽然此代码可能会解决问题,including an explanation 关于如何以及为什么解决问题将真正有助于提高您的帖子质量,并可能导致更多的赞成票。请记住,您正在为将来的读者回答问题,而不仅仅是现在提问的人。请edit您的回答添加解释并说明适用的限制和假设。以上是关于在 Java 中解码 URI 查询字符串的主要内容,如果未能解决你的问题,请参考以下文章