URL编码

概念就不啰嗦了,直接上维基百科:传送门

简单的来说,当你提交 POST 请求,并且 RequestBody 的类型是 application/x-www-form-urlencoded 时,就需要用URL编码了。

而这个工作一般不需要你手动做,常见的Web框架都帮你处理好了。

 

encodeURI 和 encodeURIComponent

JavaScript 中常常会见到这两个函数,发 POST 请求的时候,同样也是不需要你做任何事情的,但是如果是 GET 请求的话,就会需要用到这两个函数了。

那它们具体有什么区别?怎么用呢?

这里有一篇文章就讲的非常好:http://stackoverflow.com/questions/75980/best-practice-escape-or-encodeuri-encodeuricomponent

总结一下就是:

如果你的URL是这样的:

那你的处理方式就应该是这样的:

encodeURI('http://www.test.com/?.html') + '?' + encodeURIComponent('q') + '=' + encodeURIComponent('select count(*) from user where date>='2014')

 

当然这是最完整的写法,如果有些地方你自己知道没有特殊字幕,那么就没必要写那么复杂了。

那 encodeURI 和 encodeURIComponent 跟 URL编码比有什么区别呢?

主要区别就是它少编了一些符号,因为完整的URI,前半部分的 URL 和后半部分的 QueryString 中的特殊字符是不一样的,所以处理起来也不一样。

MDN文档:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURI

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent

 

Java 中遇到的问题

如果你的 Java 程序作为服务端,不管客户端用了哪种编码方式,你只要一个方法就搞定了。

那就是URLDecoder.decode

 

但是当把 Java 作为客户端去调其他地址的时候就出问题了!

我这里有一个需求:

用 Spring 的 RestTemplate 去掉一个 RestFul 接口,URL 是这样的:http://www.test.com/?q=select count(*) from user where date >= 2014

和明显我不能直接把这个 URL 传给 RestTemplate ,所以我先用URLEncoder.encode对后面那串 SQL 进行了编码,然后再传给了 RestTemplate。

 

第一个问题来了,理论上这里是对 QueryString 进行编码,所以需要用 encodeURIComponent,但是 Java 中竟然没有。。。

还好在网上找到了实现方法:

public static String encodeURIComponent(String s)
{
    String result = null;

    try
    {
        result = URLEncoder.encode(s, "utf-8")
                .replaceAll("\\+", "%20")
                .replaceAll("\\%21", "!")
                .replaceAll("\\%27", "'")
                .replaceAll("\\%28", "(")
                .replaceAll("\\%29", ")")
                .replaceAll("\\%7E", "~");
    }

    // This exception should never occur.
    catch (UnsupportedEncodingException e)
    {
        result = s;
    }

    return result;
}

 

第一个问题解决后,第二个问题来了:

RestTemplate对我的 URL 又进行了一个URLEncoder.encode ,可我的 URL 是已经编码过的,再编码一次明显就出错了。

这个问题纠结了好久,后来发现可以这么解决:

先创建一个URI 对象,然后不要传String类型的 URL,而是传一个对象,这样RestTemplate就不会对此一举了。

 

至此,问题解决。但是,复杂参数还是尽量不要放在 QueryString 里,不然坑很多…

 

本作品由 Dozer 创作,采用 知识共享署名-非商业性使用 4.0 国际许可协议 进行许可。