首页 > 代码库 > Apache commons 之 codec 深入学习以及URLCodec

Apache commons 之 codec 深入学习以及URLCodec

         我们在入门代码里,写了一些示例,感觉貌似这个类,就只有这么些内容,打开javadoc再看看,发现这个包里货还真不少。

Commons Codec 1.4 API

Packages

org.apache.commons.codec

A small set of interfaces used by the various implementations in the sub-packages.

org.apache.commons.codec.binary

Base64, Binary, and Hexadecimal String encoding and decoding.

org.apache.commons.codec.digest

Operations to simplifiy common MessageDigest tasks.

org.apache.commons.codec.language

Language and phonetic encoders.

org.apache.commons.codec.net

Network related encoding and decoding.

 

 首先看看一些URL编码相关的知识。

简介

当我们每天上网冲浪时,有一些技术我们无时无刻不在面对。有数据本身(网页),数据的格式化,能够让我们获取数据的传输机制,以及让Web网络能够真正成为Web的基础及根本:从一页到另一页的链接。这些链接都是URL。

HTTP URL语法

对于HTTP URL (使用http 或 https 协议),URL的scheme描述部分定义了数据的路径(path),后面是可选的query 和fragment

path 部分看上去是一个分层的结构,类似于文件系统中文件夹和文件的分层结构。path由"/"字符开始,每一个文件夹由"/"分隔,最后是文件。例如"/photos/egypt/cairo/first.jpg"有四个路径片段(segment):"photos"、"egypt"、"cairo" 和 "first.jpg",可以由此推出:"first.jpg"文件在文件夹"cairo"中,而"egypt"文件夹位于web站点的根文件夹"photos"里面。

URL 语法

http URL方案最初由 RFC 1738 定义(实际上,在之前的 RFC 1630也有涉及),而在 http URL 方案被重新定义之前,整个 URL 语法就已经由扩展几次 以适应发展的规范进化为一套 统一资源标识符(Uniform Resource Identifiers 即 URIs)

对于 URLs 如何拼装,各部分如何分隔有一套语法。例如:"://"分隔方案主机部分。主机路径片段部分由"/"分隔,而查询部分紧跟在"?"之后。这意味着有些字符为语法保留。有些为整个URIs保留,而有些则被特定方案保留。所有出现在不应出现位置的 保留符(例如路径片段——以文件名为例——可能包含"?")必须被URL 编码

URL编码将字符转变成对 URL 解析无意义的无害形式。它将字符转化成为一种特定字符编码的字节序列,然后将字节转换为16进制形式,并将其前面加上"%"。问号的 URL 编码形式为"%3F"。

我们可以将指向 "to_be_or_not_to_be?.jpg"图片的 URL 写成:"http://example.com/to_be_or_not_to_be%3F.jpg",这样就没有人会认为这儿可能由一个查询部分了。

现今多数浏览器显示 URLs 前都会对其解码(将百分号编码字节转回其原本字符),并在获取其网络资源的时候重新编码。这样一来,很多用户从未意识到编码的存在。

另一方面,网页作者,开发者必须明确认识到这一点,因为这里存在着很多陷阱。

URL常见陷阱

如果你正和URL打交道,了解下能够避免的常见陷阱绝对是值得的。现在我们给大家介绍下不仅限于此的一些常见陷阱。

使用哪类字符编码?

URL编码规范并没有定义使用何种字符编码形式去编码字节。一般的ASCII字母数字字符并不需要转义,但是ASCII之外的保留字需要(例如法语单词“n?ud”中的"?")。我们必须提出疑问,应该使用哪类字符编码来编码URL字节。

当然如果只有Unicode的话,这个世界就会清净很多。因为每个字符都包含其中,但是它只是一个集合,或者说是列表如果你愿意,它本身并不是一中编码。Unicode可以使用多种方式进行编码,譬如UTF-8或者UTF-16(也有其它格式),但是问题并没有解决:我们应该使用哪类字符来编码URL(通常也指URI)。

标准并没有定义一个URI应该以何种方式指定其编码,所以其必须从环境信息中进行推导。对于HTTP URL,它可以是HTML页面的编码格式,或HTTP头的。这通常会让人迷惑,也是许多错误的根源。事实上,最新版的URI标准 定义了新的URI scheme将采用UTF-8,host(甚至已有的scheme)也使用UTF-8,这让我更加怀疑:难道host和path真的可以使用不同的编码方式?

每一部分的保留字都是不同。

是的,他们是,是的,他们,是的,他们是。。。

对于一个httpd连接,路径片段部分中的空格被编码为"%20"(不,完全没有"+"),而“+”字符在路径片段部分可以保持不编码。

现在,在查询部分,一个空格可能会被编码为“+”(为了向后兼容:不要试图在URI标准去搜索他)或者“%20”,当作为“+”字符(作为个统配符的结果)会被编译为“%2B”。

这意味着“blue+light blue”字串,如果在路径部分或者查询部分,将会有不同的编码。比如得到"http://example.com/blue+light%20blue?blue%2Blight+blue"这样的编码形式,这样我们不需从语法上分析url结构,就可以推导这个url的整个结构是可能

考虑如下组装URL的Java代码片段

?

1

2

String str = "blue+light blue";

String url = "http://example.com/"+ str + "?" + str;

编码URL并不是为了转义保留字而进行的简单字符迭代,我们需要确切的知道哪个URL部份有哪些保留字,而有针对性的进行编码。

这也意味着URL重写过滤器如果不考虑合适的编码细节而对URL直接进行分段转换通常是有问题的。对URL进行编码而不考虑具体的分段规则是不切实际的。

保留字不是你想象的那样

大多数人不知道"+"在路径部分是被允许的并且特指正号而不是空格。其他类似的有:

·        "?"在查询部分允许不被转义,

·        "/"在查询部分允许不被转义,

·        "="在作为路径参数或者查询参数值以及在路径部分允许不被转义,

·        ":@-._~!$&‘()*+,;="等字符在路径部分允许不被转义,

·        "/?:@-._~!$&‘()*+,;="等字符在任何段中允许不被转义。

 这样下面的地址虽然看起来有点混乱:"http://example.com/:@-._~!$&‘()*+,=;:@-._~!$&‘()*+,=:@-._~!$&‘()*+,==?/?:@-._~!$‘()*+,;=/?:@-._~!$‘()*+,;==#/?:@-._~!$&‘()*+,;="

按照上面的规则,其实上是一个合法的地址。

如果有兴趣的话,相关的知识有非常的多,从使用的角度简单归纳下:

1.       需要通过URL转码的字符,比如汉字等;

2.       不需要通过URL转码的字符,比如12*等;

3.       需要处理的保留字,比如 #等。

如果所有的字符都要自己处理,那么开发应用会比较复杂,而且非常枯燥,org.apache.commons.codec.net这个包就提供了这些数据的处理。

我们看源代码:

package test.ffm83.commons.codec;

 

import org.apache.commons.codec.CharEncoding;

import org.apache.commons.codec.net.URLCodec;

import org.apache.commons.lang.BooleanUtils;

import org.apache.commons.lang.StringUtils;

/**

 * 通过apache commonscodecnet包进行url数据的加密

 *

 * @author范芳铭

 */

public classURLCodecUsage {

   public static void main(String[] args)throws Exception{

    URLCodecUsage usage = new URLCodecUsage();

    usage.useUrlEncode();

    usage.useSafeCharEncodeDecode();

    usage.useUnsafeEncodeDecode();

   }

 

   //普通字符的URL加密

   public void useUrlEncode() throws Exception{

    System.out.println(StringUtils.center("普通字符的URL加密", 50, "-"));

    final String msg ="范芳铭在做Url encode测试,123456";

    final URLCodec urlCodec =new URLCodec();

    String enMsg =urlCodec.encode(msg, CharEncoding.UTF_8);

    System.out.println(msg +",加密之后");

        System.out.println(enMsg);

   }

   //安全字符的编码解码

   public voiduseSafeCharEncodeDecode() throws Exception {

    System.out.println(StringUtils.center("安全字符的编码解码", 50,"-"));

        final URLCodec urlCodec =new URLCodec();

        final String plain ="abc123_-.*";

        //final String plain = "12345";

        final String encoded = urlCodec.encode(plain);

        System.out.println("plain:" + plain);

        System.out.println("encoded:" + encoded);

        System.out.println("Safe chars URL encoding test:"+ BooleanUtils.toStringYesNo(

             plain.equals(encoded)));

        System.out.println("Safe chars URL encoding test:"+ BooleanUtils.toStringYesNo(

             plain.equals(urlCodec.decode(encoded))));

   }

   

   //不安全字符的编码解码

   public void useUnsafeEncodeDecode()throwsException {

    System.out.println(StringUtils.center("不安全字符的编码解码", 50,"-"));

        final URLCodec urlCodec =new URLCodec();

        final String plain ="~!@#$%^&()+{}\"\\;:`,/[]";

        final String encoded = urlCodec.encode(plain);

        System.out.println("plain:" + plain);

        System.out.println("encoded:" + encoded);

        System.out.println("Safe chars URL encoding test:"+ BooleanUtils.toStringYesNo(

             plain.equals(encoded)));

        System.out.println("Safe chars URL encoding test:"+ BooleanUtils.toStringYesNo(

             plain.equals(urlCodec.decode(encoded))));

   }

}

运行后结果

--------------------普通字符的URL加密--------------------

范芳铭在做Urlencode测试,123456,加密之后

%E8%8C%83%E8%8A%B3%E9%93%AD%E5%9C%A8%E5%81%9AUrl+encode%E6%B5%8B%E8%AF%95%EF%BC%8C123456

--------------------安全字符的编码解码---------------------

plain:abc123_-.*

encoded:abc123_-.*

Safe chars URL encoding test:yes

Safe chars URL encoding test:yes

--------------------不安全字符的编码解码--------------------

plain:~!@#$%^&()+{}"\;:`,/[]

encoded:%7E%21%40%23%24%25%5E%26%28%29%2B%7B%7D%22%5C%3B%3A%60%2C%2F%5B%5D

Safe chars URL encoding test:no

Safechars URL encoding test:yes

Apache commons 之 codec 深入学习以及URLCodec