关于UrlEncode 一团乱麻的问题,后续彻底理解。Java中的 URLEncoder 与 URLDecoder无bug

很多开放平台都是小白开发的,对这个urlencode理解的不到位,他们总是认为java官方的urlencode有bug,需要

URLEncoder.encode("Hello World","UTF-8").replace("+", "%20") 把+号替换成 %20;所以也没办法,
看来总之把+号弄成%20能满足get和post请求,就是对的。
URLDecoder.decode("Hello%20World","UTF-8")见下图,+和%20都会把解码成空格。可见Java
做的还是不错的,考虑到了这点。

=======================初步纠结=============================

网上很多人都说:+号 urlencode之后 应该变成%20; 但是后来发现更乱,理不顺。

delphi官方的 也挺乱的,总之不安全的字符越来越多。因为后端 越来越多的字符用于表示一种特殊的含义,所以越来越多的字符不安全。

 总之这里一团乱麻,维持现状了 不再深究。

 

============================2017.03.03 16::09补充 彻底理解===================================

 来自:https://www.zhihu.com/question/38753917

-------------------------------------------------------------------------------
这个要看你实现什么标准的URLEncode的了。
--------------------------------------------------
在1994年订立的RFC1738中。
对字符串中除了-_.三个字符之外的所有非字母数字字符都替换成百分号(%)后跟两位十六进制数。
十六进制数中字母必须为大写。
http://tools.ietf.org/html/rfc1738
--------------------------
在2005年定义的RFC3986中,将针对- _.~(可见又扩充了一个波浪线字符)四个字符之外的所有非字母数字字符进行百分号编码。
在Java和PHP当中,由于历史原因,导致在进行URLEncode的时候,会将空格编码为+,而不是编码为十六进制编码%20
http://tools.ietf.org/html/rfc3895
--------------------------------------
在php当中也提供了标准的RFC1738的实现

在PHP Manual中有对两个函数的说明:

urlencode:返回字符串,此字符串中除了 - _ . 之外的所有非字母数字字符都将被替换成百分号(%)后跟两位十六进制数,空格则编码为加号(+)。此编码与 WWW 表单 POST 数据的编码方式是一样的,同时与 application/x-www-form-urlencoded 的媒体类型编码方式一样。由于历史原因,此编码在将空格编码为加号(+)方面与 RFC1738 编码(参见 rawurlencode())不同。

rawurlencode:返回字符串,此字符串中除了 - _ . 之外的所有非字母数字字符都将被替换成百分号(%)后跟两位十六进制数。这是在 RFC 1738 中描述的编码,是为了保护原义字符以免其被解释为特殊的 URL 定界符,同时保护 URL 格式以免其被传输媒体(像一些邮件系统)使用字符转换时弄乱。

我自己的理解:

从上面这篇文章中可以看到 很多人都说 java里 的 UrlEncode 把空格编码成+ 是历史的原因。且10年前都是这样说,2005年 java里就是这样了,现在2017年 都12年过去了 难道还是因为历史的原因吗,什么叫做历史的原因。

再来看另一篇文章:http://blog.csdn.net/sweetsoft/article/details/3081544

---------------------------------------------------------------------------------------------------

在调查一个错误的时候,偶然发现HTML页面中的部分Link含有+,将tag反编译了一下,发现是因为调用了Java.NET.URLEncoder的方法

public static String encode(String s, String enc)

从代码中可以很清晰的看到还特别照顾的将' '转成了'+'。由于印象中的URL编码规则应该是将空格转为%20,就google了一把,结果发现很多人都遇到了这个问题,但基本都是语焉不详。

花了1个多小时仔细搜索了一遍,线索如下:

1、在sun的bug库中找到有人认为该方法不符合RFC2396标准
http://bugs.sun.com/view_bug.do?bug_id=4616184
sun的回答说不是bug,符合HTML4.01标准

2、在W3C找到HTML标准的说明
http://www.w3.org/TR/REC-html40/interact/forms.html#h-17.13.4
在这里清楚的看到编码方式是根据ContextType的不同而区别对待的,在form的ContextType是[x-www-form-urlencoded]的时候会对form中的键/值对进行编码,空格被转义成+,其他字符按照[RFC1738]标准处理成%HH的形式。

3、回头再看URLEncoder
发现该类的注释中很明确的写明了:
converting a String to the application/x-www-form-urlencoded MIME format

从以上的结果看来%20似乎只是在使用上的一个误解,因为%20可以被解析成空格,所以就理所当然的认为空格应该被转义为%20。

再进一步,对Java/.Net/JavaScript的相关函数进行下测试,结果发现Java(1.5)与.Net(2.0)的情况一致,但JavaScript的函数还是将空格转换成了%20。看来这个问题的误解完全来自于js的错误……

=====================================================================

看了这篇文章后 再去理解空格的问题,你会发现有三个个协议标准:RFC1738、RFC2396、HTML4.01;

打开上文中的两个链接来看下:

 

官方说这不是一个bug,我猜测可能是名字上的叫法 让人误解,UrlEncode 应该叫 PostUrlEncode;或者叫WWWFormUrlEncode类。

因为http协议中 有post和get提交:

1.如果是get提交 或者是路径的话 如: http://www.bai du.com?wo=he he&ni=abc 就应该遵循RFC1738、RFC2396;就变成:http://www.bai%20du.com?wo=he%20he&ni=abc;

2.如果是post提交:因为post提交的参数依然是被弄成键值对的方式传递的类似GET的QueryString方式,即需要提交的参数应该是: wo=he he&ni=abc;但是由于 html是一种常用语言,它里面有post提价方式,他也有自己的规范,他规定post生成的键值对参数中 参数的值如果有空格应该编码成+号(注意不是%20)见上面链接打开后的下图:

 Java官方的URLEncoder.encode 实际上是为了post请求的content-type为x-www-form-urlencoded来设计的。所以没有什么bug可言。

=============================

结论:

1.资源路径中含有空格时应该转码为%20,

举例:http://www.baidu.com/he he/index.jsp -----> http://www.baidu.com/he%20he/index.jsp

2.get请求的QueryString里含有空格的话应该转码为%20;

举例:http://www.abc.com?wo=he he ------> http://www.abc.com?wo=he%20he

3.post请求时,content-type = application/x-www-form-urlencoded (一般默认都是这个)时,空格应该转码为+;

举例:向http://www.abc.com/发post请求,参数的值有空格,最终的参数键值对是 wo=he+he; 

2017-04-12 续集。。。。。。。。

 

 

 2017.11.05补充。。。。。。。。。。。。。。

get请求的时候可以用,TNetEncoding.URL.EncodeQuery,

post请求的时候可以用,TNetEncoding.URL.EncodeForm

2019-11-03 补充。。。。。。。。。。。。

procedure TfrmAesForm.Button3Click(Sender: TObject);
begin
  {
    空格的问题,根据国际URL标准,GET请求是包含在路径里的,所以与Post请求的标准不同

    GET请求参数包含在URL路径里,他们有一个标准 RFC1738,RFC3986; 此标准要求空格转为%20

    POST请求参数不包含在URL路径里,他们的参数传输有一个自己的标准  application/x-www-form-urlencoded MIME format; 此标准要求空格转为+



  }

  Memo1.Lines.Add(TNetEncoding.URL.EncodeQuery(' '));//%20 GET请求的参数用这个URLEncode

  Memo1.Lines.Add(TNetEncoding.URL.EncodeForm(' '));//+ POST请求的参数用这个URLEncode

  Memo1.Lines.Add(TNetEncoding.URL.Encode(' '));//+ get提交的时候不要用这个,这个会搞成+
end;

原文地址:https://www.cnblogs.com/del88/p/6496825.html