摘要:url编码(百分号编码)是对字节流编码的,而网页信息编码成字节流有很多种编码方式,我们探讨的是浏览器、JavaScript及服务器在不同情况下,会将网页信息如何编码成字节流。
从目前的http抓包来看,网页发送的请求最终都是ASCII编码的二进制数据流,ASCII解码数据流时,我们能看到请求行,请求头和请求体。
目前的浏览器中,http请求头中 已经不存在 Accept-Charset 字段了。
Accept-Charset:GB2312,utf-8;q=0.7,*;q=0.7
post提交表单时:下面的 charset=utf-8 字段 ,现在的浏览器已经没这个字段了。
也就是说:http请求体中的编码方式不指定,但浏览器会根据网页编码情况和表单编码的设置,对请求体【也就是post提交的表单数据】进行编码。服务器解析时,就默认这个是由本网站的网页提交的,解码时就采用本网站事先规定好的编码方式。
Content-Type: application/x-www-form-urlencoded;charset=utf-8
一、url与uri的区别
URI:统一资源标志符URI,就是在某一规则下能把一个资源独一无二地标识出来。
URL:统一资源定位符URL,就是用定位的方式实现的URI。
URN:统一资源命名符URN,就是用独一无二的名字来实现URI。
大白话:URI 包括了 URL 和 URN。【URL和URN采用不同的方式来标识资源】
当然因为协议的要求,如JAVA 的URI转换中,不希望出现”[“和”]”。当然有些URL中可能出现 “[“或”]”,这个东西不符合 URI。所以 不能说 全部的URL 都是 URI。
二、url格式
通常而言,我们所熟悉的 URL 的常见定义格式为:
scheme://host[:port#]/path/…/[url-params][?query-string][#anchor]
scheme //有我们很熟悉的http、https、ftp以及著名的ed2k,迅雷的thunder等。 host //HTTP服务器的IP地址或者域名 port# //HTTP服务器的默认端口是80,这种情况下端口号可以省略。如果使用了别的端口,必须指明,例如tomcat的默认端口是8080 http://localhost:8080/ path //访问资源的路径 url-params //所带参数 query-string //发送给http服务器的数据 anchor //锚点定位 就是文章里面的标题,浏览器可以直接跳到具体的标题那节
三、url编码规范史
url的目的就是定位资源,而url编码 的目的就是 为了 创建 url。url编码里面有保留字,就是为了对url里面的冲突内容 进行转义。
核心总结:
以前的url编码,默认字节流是 ASCII编码。url解码字节流后再用ASCII码解码就能知道原来的信息。后来因为各国的文字编码不同,如果用不同的文字编码生成字节流然后url编码,当url解码后不知道用哪种方式解码了。
所以,后来决定 RFC 3986,建议所有新的URI必须对未保留字符不加以百分号编码;其它字符建议先转换为UTF-8字节序列, 然后对其字节值使用百分号编码。此前的URI不受此标准的影响。【按道理来说,编码问题应该解决了】
但是因为历史原因,部分浏览器的url ,还没有完全采用utf-8编码。说白了大家统一认为path路径是用utf-8编码的没有问题,但是querystring 查询串该怎么编码,意见不统一。
这时,JavaScript 因为内部编码是(ucs-2 或者 utf-16 不确定),JavaScript的URL编码输出结果是UTF-8【或者Unicode排列值,不过这个已经废弃了】
所以,前端开发,要先了解一些浏览器url编码问题,然后尽量用JavaScript编码url。
二进制数据
1994年发布的RFC 1738规定, URI中的二进制数据应该表示为字节的序列,然后对每个字节按照上述方式百分号编码. 例如,字节值0F (十六进制)应表示为”%0F
“, 字节值41(十六进制)应表示为”A
“或”%41
“. 优先使用未保留字符来表示这些字节值,因为这使得URL更短.【这些都是ASCII编码 字符”A”对应 十六进制41】
RFC1738 规定:
“…Only alphanumerics [0-9a-zA-Z], the special characters “$-_.+!*'(),” [not including the quotes – ed], and reserved characters used for their reserved purposes may be used unencoded within a URL.”
“只有字母和数字[0-9a-zA-Z]、一些特殊符号”$-_.+!*'(),”[不包括双引号]、以及某些保留字,才可以不经过编码直接用于URL。”
字符数据
二进制数据的百分号编码过程已经被外推到字符数据,甚至到不适合或未被完全规范的地步. 在WWW初创阶段,仅仅处理ASCII字符是否编码问题,还没有什么问题。但随后发展到对非ASCII字符如何在URI中编码,缺少标准规范的情况下导致了歧义性的解释URI的错误。
大白话, 如基于RFC 1738与2396的协议规定,字符数据先要根据某种字符编码转换为字节流,然后再表示为URI。如果URI不提供是何种字符编码的提示信息,那么这个URI难以可靠的解析。【互联网早期,URI默认都是ASCII编码的字节流,所以解析没问题。后来各国文字编码的字节流,编码成url后,服务器解析url,然后将字节流解码成哪种编码就不知道了】
当前标准
2005年1月发布的RFC 3986,建议所有新的URI必须对无需编码的字符(下面红字RFC3986的规定中可出现的字符)不加以百分号编码;其它字符建议先转换为UTF-8字节序列, 然后对其字节值使用百分号编码(即URL编码)。此前的URI不受此标准的影响。
RFC3986文档规定,Url中只允许包含英文字母(a-zA-Z)、数字(0-9)、-_.~4个特殊字符以及所有保留字符。
非标准的实现
有一些不符合标准的把Unicode字符在URI中表示为: %uxxxx
, 其中xxxx是用4个十六进制数字表示的Unicode的码位值。任何RFC都没有这样的字符表示方法,并且已经被W3C拒绝。第三版的ECMA-262仍然包含函数escape(string)
使用这种语法, 但也有函数encodeURI(uri)
转换字符到UTF-8字节序列并用百分号编码每个字节。
application/x-www-form-urlencoded类型
当HTML表单中的数据被提交时,表单的域名与值被编码并通过HTTP的GET或者POST方法甚至更古远的email把请求发送给服务器。这里的编码方法采用了一个非常早期的通用的URI百分号编码方法,并且有很多小的修改如新行规范化以及把空格符的编码”%20
“替换为”+
” . 按这套方法编码的数据的MIME类型是application/x-www-form-urlencoded
, 当前仍用于(虽然非常过时了)HTML与XForms规范中. 此外,CGI规范包括了web服务器如何解码这类数据、利用这类数据的内容。
如果发送的是HTTP GET请求, application/x-www-form-urlencoded数据包含在所请求URI的查询成分中. 如果发送的是HTTP POST请求或通过email, 数据被放置在消息体中,媒体类型的名字被包含在消息的Content-Type头内部。