zoukankan      html  css  js  c++  java
  • 关于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;

  • 相关阅读:
    linux基本命令
    Linux中常用的50个命令
    Selenium2之XPath定位
    Selenium2浏览器启动及配置
    python学习内容.05
    python学习内容.04
    python学习内容.03
    python学习内容.02
    python学习内容.01
    RESTful
  • 原文地址:https://www.cnblogs.com/del88/p/6496825.html
Copyright © 2011-2022 走看看