对 url 中含有的中文进行转码操作


一般情况下,将带有中文的 url 拷贝到开发工具,开发工具都会有相应的转码(自动转码),

现在大部分的浏览器也可以对含有中文的 url 进行转码(自动转码)

情景说明

android

安卓系统,能够识别中文路径:

https://spdbimg.idoupiao.com/film/my/美国队长3

IOS

苹果系统,不能够识别中文路径:

https://spdbimg.idoupiao.com/film/my/美国队长3

必须将以上路径进行转码为下来形式才可以访问:

https://spdbimg.idoupiao.com/film/my/%E7%BE%8E%E5%9B%BD%E9%98%9F%E9%95%BF3

这和他们各自的战略定位有关系。。。


编码实现

1、先寻找有没有已经实现类似功能的成熟工具。

2、找到 JDK 提供的 URLEncoder 类的 encode 方法基本满足需求。

3、测试是否满足当下需求。

经过测试发现,JDK 提供的 URLEncoder 类的 encode 方法会将 ':' 和 '/' 等字符也进行编码。

4、查找 JDK 提供的 URLEncoder 类的 encode 方法 相关源码。

5、发现可以进行部分改造满足当前需求,重写 URLEncoder 类,并将其设置为私有静态类,多人合作时,防止他人误用。

6、改造完成进行验证型测试。

添加以下两条语句:


// 排除这两个特殊字符的编码
dontNeedEncoding.set(':');
dontNeedEncoding.set('/');

重写后的 URLEncoder 类:


/**
* Utility class for HTML form encoding. This class contains static methods
* for converting a String to the <CODE>application/x-www-form-urlencoded</CODE> MIME
* format. For more information about HTML form encoding, consult the HTML
* <A HREF="http://www.w3.org/TR/html4/">specification</A>.
*
* <p>
* When encoding a String, the following rules apply:
*
* <ul>
* <li>The alphanumeric characters &quot;{@code a}&quot; through
* &quot;{@code z}&quot;, &quot;{@code A}&quot; through
* &quot;{@code Z}&quot; and &quot;{@code 0}&quot;
* through &quot;{@code 9}&quot; remain the same.
* <li>The special characters &quot;{@code .}&quot;,
* &quot;{@code -}&quot;, &quot;{@code *}&quot;, and
* &quot;{@code _}&quot; remain the same.
* <li>The space character &quot; &nbsp; &quot; is
* converted into a plus sign &quot;{@code +}&quot;.
* <li>All other characters are unsafe and are first converted into
* one or more bytes using some encoding scheme. Then each byte is
* represented by the 3-character string
* &quot;<i>{@code %xy}</i>&quot;, where <i>xy</i> is the
* two-digit hexadecimal representation of the byte.
* The recommended encoding scheme to use is UTF-8. However,
* for compatibility reasons, if an encoding is not specified,
* then the default encoding of the platform is used.
* </ul>
*
* <p>
* For example using UTF-8 as the encoding scheme the string &quot;The
* string ü@foo-bar&quot; would get converted to
* &quot;The+string+%C3%BC%40foo-bar&quot; because in UTF-8 the character
* ü is encoded as two bytes C3 (hex) and BC (hex), and the
* character @ is encoded as one byte 40 (hex).
*
* @author Herb Jellinek
* @since JDK1.0
*/
private static class URLEncoder {
static BitSet dontNeedEncoding;
static final int caseDiff = ('a' - 'A');
static String dfltEncName = null; static { /* The list of characters that are not encoded has been
* determined as follows:
*
* RFC 2396 states:
* -----
* Data characters that are allowed in a URI but do not have a
* reserved purpose are called unreserved. These include upper
* and lower case letters, decimal digits, and a limited set of
* punctuation marks and symbols.
*
* unreserved = alphanum | mark
*
* mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"
*
* Unreserved characters can be escaped without changing the
* semantics of the URI, but this should not be done unless the
* URI is being used in a context that does not allow the
* unescaped character to appear.
* -----
*
* It appears that both Netscape and Internet Explorer escape
* all special characters from this list with the exception
* of "-", "_", ".", "*". While it is not clear why they are
* escaping the other characters, perhaps it is safest to
* assume that there might be contexts in which the others
* are unsafe if not escaped. Therefore, we will use the same
* list. It is also noteworthy that this is consistent with
* O'Reilly's "HTML: The Definitive Guide" (page 164).
*
* As a last note, Intenet Explorer does not encode the "@"
* character which is clearly not unreserved according to the
* RFC. We are being consistent with the RFC in this matter,
* as is Netscape.
*
*/ 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(' '); /* encoding a space to a + is done
* in the encode() method */
dontNeedEncoding.set('-');
dontNeedEncoding.set('_');
dontNeedEncoding.set('.');
dontNeedEncoding.set('*'); // 排除这两个特殊字符的编码
dontNeedEncoding.set(':');
dontNeedEncoding.set('/'); dfltEncName = AccessController.doPrivileged(
new GetPropertyAction("file.encoding")
);
} /**
* You can't call the constructor.
*/
private URLEncoder() { } /**
* Translates a string into {@code x-www-form-urlencoded}
* format. This method uses the platform's default encoding
* as the encoding scheme to obtain the bytes for unsafe characters.
*
* @param s {@code String} to be translated.
* @deprecated The resulting string may vary depending on the platform's
* default encoding. Instead, use the encode(String,String)
* method to specify the encoding.
* @return the translated {@code String}.
*/
@Deprecated
public static String encode(String s) { String str = null; try {
str = encode(s, dfltEncName);
} catch (UnsupportedEncodingException e) {
// The system should always have the platform default
} return str;
} /**
* Translates a string into {@code application/x-www-form-urlencoded}
* format using a specific encoding scheme. This method uses the
* supplied encoding scheme to obtain the bytes for unsafe
* characters.
* <p>
* <em><strong>Note:</strong> The <a href=
* "http://www.w3.org/TR/html40/appendix/notes.html#non-ascii-chars">
* World Wide Web Consortium Recommendation</a> states that
* UTF-8 should be used. Not doing so may introduce
* incompatibilities.</em>
*
* @param s {@code String} to be translated.
* @param enc The name of a supported
* <a href="../lang/package-summary.html#charenc">character
* encoding</a>.
* @return the translated {@code String}.
* @exception UnsupportedEncodingException
* If the named encoding is not supported
* @see URLDecoder#decode(java.lang.String, java.lang.String)
* @since 1.4
*/
public static String encode(String s, String enc)
throws UnsupportedEncodingException { boolean needToChange = false;
StringBuffer out = new StringBuffer(s.length());
Charset charset;
CharArrayWriter charArrayWriter = new CharArrayWriter(); if (enc == null)
throw new NullPointerException("charsetName"); try {
charset = Charset.forName(enc);
} catch (IllegalCharsetNameException e) {
throw new UnsupportedEncodingException(enc);
} catch (UnsupportedCharsetException e) {
throw new UnsupportedEncodingException(enc);
} for (int i = 0; i < s.length();) {
int c = (int) s.charAt(i);
//System.out.println("Examining character: " + c);
if (dontNeedEncoding.get(c)) {
if (c == ' ') {
c = '+';
needToChange = true;
}
//System.out.println("Storing: " + c);
out.append((char)c);
i++;
} else {
// convert to external encoding before hex conversion
do {
charArrayWriter.write(c);
/*
* If this character represents the start of a Unicode
* surrogate pair, then pass in two characters. It's not
* clear what should be done if a bytes reserved in the
* surrogate pairs range occurs outside of a legal
* surrogate pair. For now, just treat it as if it were
* any other character.
*/
if (c >= 0xD800 && c <= 0xDBFF) {
/*
System.out.println(Integer.toHexString(c)
+ " is high surrogate");
*/
if ( (i+1) < s.length()) {
int d = (int) s.charAt(i+1);
/*
System.out.println("\tExamining "
+ Integer.toHexString(d));
*/
if (d >= 0xDC00 && d <= 0xDFFF) {
/*
System.out.println("\t"
+ Integer.toHexString(d)
+ " is low surrogate");
*/
charArrayWriter.write(d);
i++;
}
}
}
i++;
} while (i < s.length() && !dontNeedEncoding.get((c = (int) s.charAt(i)))); charArrayWriter.flush();
String str = new String(charArrayWriter.toCharArray());
byte[] ba = str.getBytes(charset);
for (int j = 0; j < ba.length; j++) {
out.append('%');
char ch = Character.forDigit((ba[j] >> 4) & 0xF, 16);
// converting to use uppercase letter as part of
// the hex value if ch is a letter.
if (Character.isLetter(ch)) {
ch -= caseDiff;
}
out.append(ch);
ch = Character.forDigit(ba[j] & 0xF, 16);
if (Character.isLetter(ch)) {
ch -= caseDiff;
}
out.append(ch);
}
charArrayWriter.reset();
needToChange = true;
}
} return (needToChange? out.toString() : s);
}
}

测试代码:

    @Test
public void testReplace() throws UnsupportedEncodingException { // https://ojjqzz83h.qnssl.com/film/my/美国队长3?imageView2/1/w/140/h/90/interlace/0/q/100
// https://spdbimg.idoupiao.com/film/my/%E7%BE%8E%E5%9B%BD%E9%98%9F%E9%95%BF3 String oldImgUrl = "https://spdbimg.idoupiao.com/film/my/美国队长3"; oldImgUrl = URLEncoder.encode(oldImgUrl, "UTF-8"); // oldImgUrl = new String(Base64.getEncoder().encode(oldImgUrl.getBytes())); String oldDomain = "spdbimg.idoupiao.com";
String newDomain = "ojjqzz83h.qnssl.com";
String suffix = "?imageView2/1/w/140/h/90/interlace/0/q/100"; String newImgUrl = StringUtils.replace(oldImgUrl, oldDomain, newDomain).concat(suffix); System.out.println("newImgUrl === " + newImgUrl); }

完整代码如下:


package com.github.ljmatlight.util; import org.junit.Test;
import sun.security.action.GetPropertyAction; import java.io.CharArrayWriter;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.nio.charset.Charset;
import java.nio.charset.IllegalCharsetNameException;
import java.nio.charset.UnsupportedCharsetException;
import java.security.AccessController;
import java.util.BitSet; /**
* Description:对 url 中含有的中文进行转码操作
* <br /> Author:ljmatlight
*/
public class StringTest { @Test
public void testReplace() throws UnsupportedEncodingException { // https://ojjqzz83h.qnssl.com/film/my/美国队长3?imageView2/1/w/140/h/90/interlace/0/q/100
// https://spdbimg.idoupiao.com/film/my/%E7%BE%8E%E5%9B%BD%E9%98%9F%E9%95%BF3 String oldImgUrl = "https://spdbimg.idoupiao.com/film/my/美国队长3"; oldImgUrl = URLEncoder.encode(oldImgUrl, "UTF-8"); // oldImgUrl = new String(Base64.getEncoder().encode(oldImgUrl.getBytes())); String oldDomain = "spdbimg.idoupiao.com";
String newDomain = "ojjqzz83h.qnssl.com";
String suffix = "?imageView2/1/w/140/h/90/interlace/0/q/100"; String newImgUrl = StringUtils.replace(oldImgUrl, oldDomain, newDomain).concat(suffix); System.out.println("newImgUrl === " + newImgUrl); } /**
* Utility class for HTML form encoding. This class contains static methods
* for converting a String to the <CODE>application/x-www-form-urlencoded</CODE> MIME
* format. For more information about HTML form encoding, consult the HTML
* <A HREF="http://www.w3.org/TR/html4/">specification</A>.
*
* <p>
* When encoding a String, the following rules apply:
*
* <ul>
* <li>The alphanumeric characters &quot;{@code a}&quot; through
* &quot;{@code z}&quot;, &quot;{@code A}&quot; through
* &quot;{@code Z}&quot; and &quot;{@code 0}&quot;
* through &quot;{@code 9}&quot; remain the same.
* <li>The special characters &quot;{@code .}&quot;,
* &quot;{@code -}&quot;, &quot;{@code *}&quot;, and
* &quot;{@code _}&quot; remain the same.
* <li>The space character &quot; &nbsp; &quot; is
* converted into a plus sign &quot;{@code +}&quot;.
* <li>All other characters are unsafe and are first converted into
* one or more bytes using some encoding scheme. Then each byte is
* represented by the 3-character string
* &quot;<i>{@code %xy}</i>&quot;, where <i>xy</i> is the
* two-digit hexadecimal representation of the byte.
* The recommended encoding scheme to use is UTF-8. However,
* for compatibility reasons, if an encoding is not specified,
* then the default encoding of the platform is used.
* </ul>
*
* <p>
* For example using UTF-8 as the encoding scheme the string &quot;The
* string ü@foo-bar&quot; would get converted to
* &quot;The+string+%C3%BC%40foo-bar&quot; because in UTF-8 the character
* ü is encoded as two bytes C3 (hex) and BC (hex), and the
* character @ is encoded as one byte 40 (hex).
*
* @author Herb Jellinek
* @since JDK1.0
*/
private static class URLEncoder {
static BitSet dontNeedEncoding;
static final int caseDiff = ('a' - 'A');
static String dfltEncName = null; static { /* The list of characters that are not encoded has been
* determined as follows:
*
* RFC 2396 states:
* -----
* Data characters that are allowed in a URI but do not have a
* reserved purpose are called unreserved. These include upper
* and lower case letters, decimal digits, and a limited set of
* punctuation marks and symbols.
*
* unreserved = alphanum | mark
*
* mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"
*
* Unreserved characters can be escaped without changing the
* semantics of the URI, but this should not be done unless the
* URI is being used in a context that does not allow the
* unescaped character to appear.
* -----
*
* It appears that both Netscape and Internet Explorer escape
* all special characters from this list with the exception
* of "-", "_", ".", "*". While it is not clear why they are
* escaping the other characters, perhaps it is safest to
* assume that there might be contexts in which the others
* are unsafe if not escaped. Therefore, we will use the same
* list. It is also noteworthy that this is consistent with
* O'Reilly's "HTML: The Definitive Guide" (page 164).
*
* As a last note, Intenet Explorer does not encode the "@"
* character which is clearly not unreserved according to the
* RFC. We are being consistent with the RFC in this matter,
* as is Netscape.
*
*/ 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(' '); /* encoding a space to a + is done
* in the encode() method */
dontNeedEncoding.set('-');
dontNeedEncoding.set('_');
dontNeedEncoding.set('.');
dontNeedEncoding.set('*'); // 排除这两个特殊字符的编码
dontNeedEncoding.set(':');
dontNeedEncoding.set('/'); dfltEncName = AccessController.doPrivileged(
new GetPropertyAction("file.encoding")
);
} /**
* You can't call the constructor.
*/
private URLEncoder() { } /**
* Translates a string into {@code x-www-form-urlencoded}
* format. This method uses the platform's default encoding
* as the encoding scheme to obtain the bytes for unsafe characters.
*
* @param s {@code String} to be translated.
* @deprecated The resulting string may vary depending on the platform's
* default encoding. Instead, use the encode(String,String)
* method to specify the encoding.
* @return the translated {@code String}.
*/
@Deprecated
public static String encode(String s) { String str = null; try {
str = encode(s, dfltEncName);
} catch (UnsupportedEncodingException e) {
// The system should always have the platform default
} return str;
} /**
* Translates a string into {@code application/x-www-form-urlencoded}
* format using a specific encoding scheme. This method uses the
* supplied encoding scheme to obtain the bytes for unsafe
* characters.
* <p>
* <em><strong>Note:</strong> The <a href=
* "http://www.w3.org/TR/html40/appendix/notes.html#non-ascii-chars">
* World Wide Web Consortium Recommendation</a> states that
* UTF-8 should be used. Not doing so may introduce
* incompatibilities.</em>
*
* @param s {@code String} to be translated.
* @param enc The name of a supported
* <a href="../lang/package-summary.html#charenc">character
* encoding</a>.
* @return the translated {@code String}.
* @exception UnsupportedEncodingException
* If the named encoding is not supported
* @see URLDecoder#decode(java.lang.String, java.lang.String)
* @since 1.4
*/
public static String encode(String s, String enc)
throws UnsupportedEncodingException { boolean needToChange = false;
StringBuffer out = new StringBuffer(s.length());
Charset charset;
CharArrayWriter charArrayWriter = new CharArrayWriter(); if (enc == null)
throw new NullPointerException("charsetName"); try {
charset = Charset.forName(enc);
} catch (IllegalCharsetNameException e) {
throw new UnsupportedEncodingException(enc);
} catch (UnsupportedCharsetException e) {
throw new UnsupportedEncodingException(enc);
} for (int i = 0; i < s.length();) {
int c = (int) s.charAt(i);
//System.out.println("Examining character: " + c);
if (dontNeedEncoding.get(c)) {
if (c == ' ') {
c = '+';
needToChange = true;
}
//System.out.println("Storing: " + c);
out.append((char)c);
i++;
} else {
// convert to external encoding before hex conversion
do {
charArrayWriter.write(c);
/*
* If this character represents the start of a Unicode
* surrogate pair, then pass in two characters. It's not
* clear what should be done if a bytes reserved in the
* surrogate pairs range occurs outside of a legal
* surrogate pair. For now, just treat it as if it were
* any other character.
*/
if (c >= 0xD800 && c <= 0xDBFF) {
/*
System.out.println(Integer.toHexString(c)
+ " is high surrogate");
*/
if ( (i+1) < s.length()) {
int d = (int) s.charAt(i+1);
/*
System.out.println("\tExamining "
+ Integer.toHexString(d));
*/
if (d >= 0xDC00 && d <= 0xDFFF) {
/*
System.out.println("\t"
+ Integer.toHexString(d)
+ " is low surrogate");
*/
charArrayWriter.write(d);
i++;
}
}
}
i++;
} while (i < s.length() && !dontNeedEncoding.get((c = (int) s.charAt(i)))); charArrayWriter.flush();
String str = new String(charArrayWriter.toCharArray());
byte[] ba = str.getBytes(charset);
for (int j = 0; j < ba.length; j++) {
out.append('%');
char ch = Character.forDigit((ba[j] >> 4) & 0xF, 16);
// converting to use uppercase letter as part of
// the hex value if ch is a letter.
if (Character.isLetter(ch)) {
ch -= caseDiff;
}
out.append(ch);
ch = Character.forDigit(ba[j] & 0xF, 16);
if (Character.isLetter(ch)) {
ch -= caseDiff;
}
out.append(ch);
}
charArrayWriter.reset();
needToChange = true;
}
} return (needToChange? out.toString() : s);
}
} }

作者:随风浮云

出处:http://www.cnblogs.com/ljmatlight

本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明。

文中有不妥或者错误的地方,欢迎勘误,如果你有更好的建议,可以给我留言讨论,共同进步。

互联网技术时效性较强,引用请慎重。


对 url 中含有的中文进行转码操作的更多相关文章

  1. iOS边练边学--NSURLSession、NSURLSessionTask的介绍与使用以及url中包含了中文的处理方法

    一.NSURLSession.NSURLSessionTask的使用步骤 首先创建NSURLSession对象 通过NSURLSession对象创建对应的任务 <1>NSURLSessio ...

  2. curl请求的url中含有空格

    curl请求的url中含有空格时(例如rul的参数是sql查询语句,url=www.tets.com/query.php?sql=select * from t1),curl_easy_perform ...

  3. 关于Retrofit网络请求URL中含有可变参数的处理

    开题:在此默认各位看官对Retrofit.以及Okhttp已经有过一定的了解及应用,所以今天我们不谈基础入门的东西,今天我们谈在Retrofit请求接口管理类中URL参数含有动态参数的处理方式.一般我 ...

  4. 微信小程序传递URL中含有特殊字符

    小程序传递URL中含有特殊字符"="时,解决办法:先encodeURIComponent,取到值以后再decodeURIComponent 首先在A页面 var urls = en ...

  5. url编码--url中含有空格问题

    开发web服务中,发现当url中含有空格时,会报 400 error: bad request sytanx,经分析,url中含有特殊字符时,服务端可能无法识别.如+,空格,/,?,%,#,& ...

  6. iOS 的url中含有中文解决方法

    [NSURLURLWithString:urlString]生成URL对象时,iOS客户端不能正确进行网络请求,网上找到的URLEncode方法又不能完全解决问题. 方法1: NSString* en ...

  7. url中含有中文路径时访问出现404问题

    /** * URL中文字符编码转换 * @param url 含中文字符的URL * @return */ public static String getChineseURICode(String ...

  8. URL中含有+号,出现错误“请求筛选模块被配置为拒绝包含双重转义序列的请求”的解决方法

    搜索关键词中含空格,提交后被自动转成了“+”号,报如下错误: HTTP 错误 404.11 - Not Found 请求筛选模块被配置为拒绝包含双重转义序列的请求. 解决方法: 在web.config ...

  9. tomcat下获取当前路径的url中含有空格解决方法

    参考博文(http://www.360doc.com/content/11/1009/17/4602013_154657565.shtml) web项目发布到Tomcat之后,如果tomcat是安装在 ...

随机推荐

  1. mysql查看表大小

    mysql查看表大小 一:命令 show table status like 'table_name'\G; mysql> show table status like 'x'\G; . row ...

  2. Spring学习之路三——第一个Spring程序(体会IoC)

    体会IoC:Spring通过一种称作控制反转(IoC)的技术促进了松耦合.当应用了IoC,一个对象依赖的其它对象会通过被动的方式传递进来,而不是这个对象自己创建或者查找依赖对象.你可以认为IoC与JN ...

  3. Oracle问题之ORA-12560TNS:协议适配器错误

    Oracle问题之ORA-12560TNS:协议适配器错误 一.造成ORA-12560: TNS: 协议适配器错误的问题的原因有三个: 1.监听服务没有起起来.windows平台个一如下操作:开始-- ...

  4. mysql 查看索引使用情况

    show status like 'Handler_read%'; Handler_read_key  代表着一个行被索引值读取的次数,值很低表明索引不经常用到,增加索引对性能改善不高. Handle ...

  5. [转]怎么查看和修改 MySQL 的最大连接数?

    使用 MySQL 数据库的站点,当访问连接数过多时,就会出现 "Too many connections" 的错误.出现这种错误有两种情况,一种是网站访问量实在太大,服务器已经负担 ...

  6. 通过Azure 存储账号URL鉴别是标准磁盘还是高性能磁盘

    对于不知道虚拟机磁盘是标准磁盘还是高性能磁盘时,我们可以通过nslookup解析存储账号的URL,来判断存储账号的类型,从而得知虚拟磁盘的类型 1.标准存储账号的解析结果,字母"st&quo ...

  7. httpd: Could not reliably determine the server's fully qualified domain name, using ::1 for ServerName

    问题原因: httpd服务配置文件,并没有设置解析根地址,无法可靠地确定服务器的完全合格的域名 如何解决? httpd的配置文件放在 /etc/httpd/conf/目录下,去掉ServerName注 ...

  8. Java客户端工具选择:HTML?Swing?XML?

    整理下面的文章是因为个人觉得写的很好,关于java的客户端了解也并不是太多.看了下面的文章觉得很有必要贴出来,方便自己以后了解java客户端编程. Java软件设计师和管理人员经常会面临这样的难题:在 ...

  9. linkin大话面向对象--方法详解

    1,方法的参数传递机制:值传递. 首先弄懂2个概念:形参和实参. 形参(形式参数):相当于函数(Java中也把函数称之为方法)中的局部变量,在函数被调用时创建,并以传入的实参作为起始值,函数调用结束时 ...

  10. Oracl Over函数

    Oracl Over函数 简介 在介绍Over之前, 必须提到开窗函数, 与 聚 合函数一样, 开窗函数也是对行集组进行聚合计算, 但是它不像普通聚合函数那样每组只返回一个值, 开窗函数可以为每组返回 ...