URLDecoder:转义(%)模式中存在非法的十六进制字符 - 输入字符串为:“</”

31

我在尝试从我的应用程序生成.PDF文件时遇到了这个异常。

URLDecoder: Illegal hex characters in escape (%) pattern - For input string:....

以下是堆栈跟踪信息

java.lang.IllegalArgumentException: URLDecoder: Illegal hex characters in escape (%) pattern - For input string: "</"
    at java.net.URLDecoder.decode(Unknown Source)
     

以下是代码

StringBuffer outBuffer = new StringBuffer();
//some values are added to outBuffer .
String pdfXmlView = URLDecoder.decode(outBuffer.toString(), "utf-8");
在尝试使用 URLDecoder.decode() 进行解码时,它会抛出异常。我已经找到了异常的原因,是由于 outBuffer 中的 % 字符引起的。
如果有人知道如何解决这个问题,请告诉我。

输入的字符串是什么?你是如何生成PDF的?堆栈跟踪看起来像什么? - Stephen C
为什么要回滚上面格式化的文本? - developer
6个回答

59

所接受的答案存在一个严重问题,被编码的字符中有%和+符号,因此虽然这对于字符串中的%和+字符有所帮助,但由于在解码之前要去掉百分号,所以它也不能解码像%20(空格)这样的内容。

一种解决方案是替换%2B(+)和%25(%)。可以使用以下代码:

   public static String replacer(StringBuffer outBuffer) {
      String data = outBuffer.toString();
      try {
         data = data.replaceAll("%(?![0-9a-fA-F]{2})", "%25");
         data = data.replaceAll("\\+", "%2B");
         data = URLDecoder.decode(data, "utf-8");
      } catch (Exception e) {
         e.printStackTrace();
      }
      return data;
   }
"

"+" 是一个特殊字符,表示量词意义上的���个或多个出现。因此应该使用 "\+"

。"

@thegamblerrises - 这是一个正确的编辑,但通常最好在评论中发布代码更正建议,而不是直接编辑代码。http://meta.stackoverflow.com/questions/252806/when-should-i-edit-something-vs-comment-on-it-if-its-a-relatively-trivial-error - Palpatim
@fanfavorite,你能解释一下这个正则表达式在这里的作用吗?这会帮助我有所了解。如果你能解释一下这两行replaceAll的作用,那就太好了。 - john
3
第一个replaceAll是正则表达式,将任何不是另一个编码字符的百分号替换为百分号编码值。问号使后面的内容变成可选项,[0-9a-fA-F]查找这些字符/数字范围,{2}查找恰好两个字符/数字。第二个replaceAll仅将加号替换为其编码值。 - fanfavorite
有人能解释一下为什么需要这个正则表达式替换吗?如果我在对文件进行任何操作之前只是说“data.replace(“%”,“%25”)”,会发生什么?它可能遇到哪些问题? - Shubham

8
我找到了这个异常的原因。请参考URLDecoder的链接
所以,在调用URLDecoder.decode()之前,我做了这个...
public static String replacer(StringBuffer outBuffer) {

    String data = outBuffer.toString();
    try {
        StringBuffer tempBuffer = new StringBuffer();
        int incrementor = 0;
        int dataLength = data.length();
        while (incrementor < dataLength) {
            char charecterAt = data.charAt(incrementor);
            if (charecterAt == '%') {
                tempBuffer.append("<percentage>");
            } else if (charecterAt == '+') {
                tempBuffer.append("<plus>");
            } else {
                tempBuffer.append(charecterAt);
            }
            incrementor++;
        }
        data = tempBuffer.toString();
        data = URLDecoder.decode(data, "utf-8");
        data = data.replaceAll("<percentage>", "%");
        data = data.replaceAll("<plus>", "+");
    } catch(Exception e) {
        e.printStackTrace();
    }
    return data;
}

2
这个有一个很大的问题。被编码的字符串中有%和+符号,所以虽然这可以帮助处理字符串中的这些字符,但它也不能解码像%20(空格)这样的东西,因为你在解码之前已经去掉了百分号。 - fanfavorite
3
一种解决方法是将“%2B”(加号)和“%25”(百分号)进行替换。 - fanfavorite
@fanfavorite 是的,这应该是一个更好的解决方案,所以它是在 URL 中进行特殊处理吗? - Scarlett
URL解码器期望%在字符代码之前。我在上面发布了一个解决方案。 - fanfavorite

1
你可以使用这个:

String stringEncoded = URLEncoder.encode(**YOUR_TEXT**, "UTF-8");

当我使用servlet(黑暗时),我遇到了这个问题。


0
If you are facing issue only with **%**. Then this would help:

   protected static String encoder(String localTopic1){
        String localTopic =localTopic1;
        try {
            StringBuffer tempBuffer = new StringBuffer();
            int incrementor = 0;
            int dataLength = localTopic.length();
            while (incrementor < dataLength) {
            char characterAt = localTopic.charAt(incrementor);
            int next_char_index = incrementor+1;
            int third_index = next_char_index+1;
            Character charAt_nextIndex = ' ';
            char charAt_thirdIndex = ' ';
            String stringAt_nextIndex = "";

            if(next_char_index < dataLength){
                    charAt_nextIndex = localTopic.charAt(next_char_index);
                    stringAt_nextIndex = charAt_nextIndex.toString();
            }
            if(third_index < dataLength)
                    charAt_thirdIndex = localTopic.charAt(third_index);


            if (characterAt == '%') {
                    if(stringAt_nextIndex.matches("[A-F2-9]")){

                            if(charAt_thirdIndex == ' ' || charAt_thirdIndex == '%'){
                                    tempBuffer.append("<percentage>");
                            }
                            else{
                                    tempBuffer.append(characterAt);
                            }
                    }
                    else{
                            tempBuffer.append("<percentage>");
                    }

            }else {
                    tempBuffer.append(characterAt);
            }
            incrementor++;
    }
    localTopic = tempBuffer.toString();
} catch (Exception e) {
    e.printStackTrace();
}
return localTopic;
}

0

我遇到了同样的问题,当在网络上传输数据时。
提供抛出异常URLDecoder: Illegal hex characters in escape (%)的示例代码。

以下是传递字符串'Yash %'的示例Ajax代码:

var encodedData = encodeURIComponent('Yash %');

var xmlhttp = new XMLHttpRequest();
xmlhttp.open("POST", "https://yash.ssl.com:8443/ServletApp/test", true);
xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xmlhttp.send("data="+encodedData);

    xmlhttp.onreadystatechange = function() {
        if (xmlhttp.readyState==4 && xmlhttp.status==200) {
            console.log("data uploaded successfully :: ");
        }
    };

接受POST请求的Servlet代码。

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    try {
        System.out.println(" ===== ------ ===== /test | " + request.getParameter("data"));

        String networkData = URLDecoder.decode( request.getParameter("data"), "UTF-8");
        System.out.println("Ajax call data : "+ networkData);
    } catch (Exception ex) {
        ex.printStackTrace();
    }
}

正如 @Marcelo Rebouças 建议的,在解码字符串之前,我正在对其进行编码。
Java URLDecoder 类 « 字符“%”是允许的,但被解释为特殊转义序列的开始。
Javascript URL 函数 encodeURI() 和 encodeURIComponent()

// URLDecoder: Illegal hex characters in escape (%) pattern
String stringEncoded = URLEncoder.encode( request.getParameter("data"), "UTF-8");
String networkData = URLDecoder.decode( stringEncoded, "UTF-8");

-1
请检查您输入的解码器参数,传递给解码器方法的 outbuffer 应该是一个已编码的值,这样就不会出现此问题。

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