URLEncoder无法转换空格字符

时间:2011-01-19 16:26:06

标签: java url urlencode

我期待

System.out.println(java.net.URLEncoder.encode("Hello World", "UTF-8"));

输出:

Hello%20World

(20是空格的ASCII十六进制代码)

然而,我得到的是:

Hello+World

我使用了错误的方法吗?我应该使用的正确方法是什么?

17 个答案:

答案 0 :(得分:202)

这表现得如预期。 URLEncoder实现了HTML规范,以便如何对HTML表单中的URL进行编码。

来自javadocs

  

此类包含静态方法   将String转换为   application / x-www-form-urlencoded MIME   格式。

来自HTML Specification

  

application / x-www-form-urlencoded

     

使用此内容类型提交的表单   必须编码如下:

     
      
  1. 转义控件名称和值。空格字符被替换   通过`+'
  2.   

您必须更换它,例如:

System.out.println(java.net.URLEncoder.encode("Hello World", "UTF-8").replace("+", "%20"));

答案 1 :(得分:41)

空间在URL中编码为%20,在表单提交的数据中编码为+(内容类型application / x-www-form-urlencoded)。你需要前者。

使用Guava

dependencies {
     compile 'com.google.guava:guava:23.0'
     // or, for Android:
     compile 'com.google.guava:guava:23.0-android'
}

您可以使用UrlEscapers

String encodedString = UrlEscapers.urlFragmentEscaper().escape(inputString);

不要使用String.replace,这只会对空间进行编码。改为使用库。

答案 2 :(得分:25)

此类执行application/x-www-form-urlencoded - 类型编码而非百分比编码,因此将替换为+是正确的行为。

来自javadoc:

  

对String进行编码时,以下规则适用:

     
      
  • 字母数字字符“a”到“z”,“A”到“Z”和“0”到“9”保持不变。
  •   
  • 特殊字符“。”,“ - ”,“*”和“_”保持不变。
  •   
  • 空格字符“”将转换为加号“+”。
  •   
  • 所有其他字符都不安全,首先使用某种编码方案将其转换为一个或多个字节。然后每个字节由3个字符的字符串“%xy”表示,其中xy是字节的两位十六进制表示。建议使用的编码方案是UTF-8。但是,出于兼容性原因,如果未指定编码,则使用平台的默认编码。
  •   

答案 3 :(得分:13)

编码查询参数

org.apache.commons.httpclient.util.URIUtil
    URIUtil.encodeQuery(input);

如果你想在URI中转义字符

public static String escapeURIPathParam(String input) {
  StringBuilder resultStr = new StringBuilder();
  for (char ch : input.toCharArray()) {
   if (isUnsafe(ch)) {
    resultStr.append('%');
    resultStr.append(toHex(ch / 16));
    resultStr.append(toHex(ch % 16));
   } else{
    resultStr.append(ch);
   }
  }
  return resultStr.toString();
 }

 private static char toHex(int ch) {
  return (char) (ch < 10 ? '0' + ch : 'A' + ch - 10);
 }

 private static boolean isUnsafe(char ch) {
  if (ch > 128 || ch < 0)
   return true;
  return " %$&+,/:;=?@<>#%".indexOf(ch) >= 0;
 }

答案 4 :(得分:11)

Hello+World是浏览器对application/x-www-form-urlencoded请求的表单数据(GET)进行编码的方式,这是URI的查询部分的普遍接受的形式。

http://host/path/?message=Hello+World

如果将此请求发送到Java servlet,则servlet将正确解码参数值。通常,这里唯一有问题的是编码不匹配。

严格地说,HTTP或URI规范中没有要求使用application/x-www-form-urlencoded键值对来编码查询部分;查询部分只需要是Web服务器接受的形式。在实践中,这不太可能是一个问题。

将此编码用于URI的其他部分(例如路径)通常是不正确的。在这种情况下,您应该使用RFC 3986中描述的编码方案。

http://host/Hello%20World

更多here

答案 5 :(得分:4)

“+”是正确的。如果你真的需要%20,那么之后自己更换加号。

答案 6 :(得分:4)

其他答案要么提供手动字符串替换,URLEncoder实际编码为HTML格式,Apache为abandoned URIUtil,要么使用Guava的UrlEscapers。最后一个很好,除了它没有提供解码器。

Apache Commons Lang提供URLCodec,它根据URL格式rfc3986进行编码。

String encoded = new URLCodec().encode(str);
String decoded = new URLCodec().decode(str);

如果您已经在使用Spring,那么您也可以选择使用 UriUtils类。

答案 7 :(得分:2)

这对我有用

org.apache.catalina.util.URLEncoder ul = new org.apache.catalina.util.URLEncoder().encode("MY URL");

答案 8 :(得分:2)

刚刚在Android上苦苦挣扎,设法偶然发现Uri.encode(String,String),而特定于android(android.net.Uri)可能对某些人有用。

static String encode(String s,String allow)

https://developer.android.com/reference/android/net/Uri.html#encode(java.lang.String, java.lang.String)

答案 9 :(得分:1)

如果您使用码头,那么org.eclipse.jetty.util.URIUtil将解决问题。

String encoded_string = URIUtil.encodePath(not_encoded_string).toString();

答案 10 :(得分:0)

查看java.net.URI类。

答案 11 :(得分:0)

  

我使用了错误的方法吗?我应该使用的正确方法是什么?

是的,这个方法java.net.URLEncoder.encode没有用于转换&#34; &#34;到&#34; 20%&#34;根据规范(source)。

  

空间角色&#34; &#34;转换为加号&#34; +&#34;。

即使这不是正确的方法,您可以将其修改为:System.out.println(java.net.URLEncoder.encode("Hello World", "UTF-8").replaceAll("\\+", "%20"));有一个美好的一天=)。

答案 12 :(得分:0)

尽管很老,但反应很快:

Spring提供了UriUtils-通过它您可以指定编码方式以及与URI相关的部分,例如

encodePathSegment
encodePort
encodeFragment
encodeUriVariables
....

我之所以使用它们,是因为我们已经在使用Spring,即不需要附加库!

答案 13 :(得分:0)

如果你想对 URI 路径组件进行编码,你也可以使用 standard JDK 函数,例如

public static String encodeURLPathComponent(String path) {
    try {
        return new URI(null, null, path, null).toASCIIString();
    } catch (URISyntaxException e) {
        // do some error handling
    }
    return "";
}

URI 类还可用于对 URI 的不同部分或整个 URI 进行编码。

答案 14 :(得分:0)

它不是单行的,但您可以使用:

URL url = new URL("https://some-host.net/dav/files/selling_Rosetta Stone Case Study.png.aes");
URI uri = new URI(url.getProtocol(), url.getUserInfo(), url.getHost(), url.getPort(), url.getPath(), url.getQuery(), url.getRef());
System.out.println(uri.toString());

这会给你一个输出:

https://some-host.net/dav/files/selling_Rosetta%20Stone%20Case%20Study.png.aes

答案 15 :(得分:-1)

USE MyUrlEncode.URLencoding(String url,String enc)来处理问题

    public class MyUrlEncode {
    static BitSet dontNeedEncoding = null;
    static final int caseDiff = ('a' - 'A');
    static {
        dontNeedEncoding = new BitSet(256);
        int i;
        for (i = 'a'; i <= 'z'; i++) {
            dontNeedEncoding.set(i);
        }
        for (i = 'A'; i <= 'Z'; i++) {
            dontNeedEncoding.set(i);
        }
        for (i = '0'; i <= '9'; i++) {
            dontNeedEncoding.set(i);
        }
        dontNeedEncoding.set('-');
        dontNeedEncoding.set('_');
        dontNeedEncoding.set('.');
        dontNeedEncoding.set('*');
        dontNeedEncoding.set('&');
        dontNeedEncoding.set('=');
    }
    public static String char2Unicode(char c) {
        if(dontNeedEncoding.get(c)) {
            return String.valueOf(c);
        }
        StringBuffer resultBuffer = new StringBuffer();
        resultBuffer.append("%");
        char ch = Character.forDigit((c >> 4) & 0xF, 16);
            if (Character.isLetter(ch)) {
            ch -= caseDiff;
        }
        resultBuffer.append(ch);
            ch = Character.forDigit(c & 0xF, 16);
            if (Character.isLetter(ch)) {
            ch -= caseDiff;
        }
         resultBuffer.append(ch);
        return resultBuffer.toString();
    }
    private static String URLEncoding(String url,String enc) throws UnsupportedEncodingException {
        StringBuffer stringBuffer = new StringBuffer();
        if(!dontNeedEncoding.get('/')) {
            dontNeedEncoding.set('/');
        }
        if(!dontNeedEncoding.get(':')) {
            dontNeedEncoding.set(':');
        }
        byte [] buff = url.getBytes(enc);
        for (int i = 0; i < buff.length; i++) {
            stringBuffer.append(char2Unicode((char)buff[i]));
        }
        return stringBuffer.toString();
    }
    private static String URIEncoding(String uri , String enc) throws UnsupportedEncodingException { //对请求参数进行编码
        StringBuffer stringBuffer = new StringBuffer();
        if(dontNeedEncoding.get('/')) {
            dontNeedEncoding.clear('/');
        }
        if(dontNeedEncoding.get(':')) {
            dontNeedEncoding.clear(':');
        }
        byte [] buff = uri.getBytes(enc);
        for (int i = 0; i < buff.length; i++) {
            stringBuffer.append(char2Unicode((char)buff[i]));
        }
        return stringBuffer.toString();
    }

    public static String URLencoding(String url , String enc) throws UnsupportedEncodingException {
        int index = url.indexOf('?');
        StringBuffer result = new StringBuffer();
        if(index == -1) {
            result.append(URLEncoding(url, enc));
        }else {
            result.append(URLEncoding(url.substring(0 , index),enc));
            result.append("?");
            result.append(URIEncoding(url.substring(index+1),enc));
        }
        return result.toString();
    }

}

答案 16 :(得分:-3)

为URLEncoder使用字符集“ISO-8859-1