踩坑系列之[2]-30分钟轻松解决前端开发中的乱码问题

本文不会给出具体的乱码解决步骤,但会讲解前端中编解码的场景和原理。通过这些原理进而找到解决实际问题的方法论。

我们知道,在开发中经常会碰到所谓的 Unicode编码,以及 UCS, UTF-8, UTF-16编码,还有 URL编码, HTML编码,甚至还有 js转义字符, unicode转义字符这些概念。那么,在什么情况下该用何种编码,需要我们对编码有个清晰的认识。

引言

乱码,是程序开发中一个比较永恒的话题。在前端这种稍微轻量级的开发中,也存在一些编码问题,甚至更多。尤其是在涉及到跟后端交互时,更容易出现莫名其妙的乱码。

然而,乱码虽乱,但却有章可循。只要找到编码这个知识点其中的道道,乱码也就不复存在了。

这篇文章中,我将用一种看透本质的新的视角来解读前端开发中 编码 这个问题。不仅讲解 字符存储的编码解码, 还会讲解前端中特有的 URL编码解码HTML/JS转义。之所以放在一起讲,是因为我觉得我们网络上大量的文章,可能混淆了编码、转义概念上的区别。当然,事实上从广义的角度来说,转义也算是编码,比如对于html实体字符来说,我们可以称之为html编码后的结果,也可以称之为html转义字符。

在本文中,我尽可能地对编码和转义给出稍微明确的界限。目的是为了我们更好的对前端这些概念进行分类总结。我将尽可能清晰的把我的理解讲述出来,不一定完全正确,但我认为可以帮助你更加清晰地看到他们的本质。

面向字符显示设备的编码: 字符领域的基础设施–现实图形和二进制数值的映射

我们知道,在计算机中,只有二进制。基于计算机的硬件实现原理和其他因素,内存和磁盘形成了以Byte字节为单位的存储概念。而对应到数值,便是一个字节可以表达0-255个数值。因此,我们就从数字开始说起。 为了实现人类世界中各种概念,必须找到一种数字与现实世界的对应关系,这就是所谓的数字化。

仔细观察,如今计算机能够代替人类处理N多的事务,然而实际上它的使用范围也很狭窄。狭窄在—它只能处理可以数字化的东西。

何为数字化? 其实就是事物与数字能否找到对应关系。再向上层抽象的话,可以理解为现实事物能否抽象为一种数学模型。

为什么计算机可以处理文字? 那是因为人们定义了一种数字跟文字字符的对应关系。如此,计算机只需要处理数字,便相当于处理了人类的文字。

为什么计算机可以处理图像? 那是因为人们把图像分割成像素,然后定义了一种像素跟数字的对应关系,如此一来,计算机只需要处理数字便相当于在处理图像。

视频如此,音频亦是如此。比如以前有一种图像格式占用空间特别大(好像是BMP),他就是依次把图像上各个像素点的值存储下来。这种最直接的存储方式,就类似于我今天在这里所讲的unicode字符基础设施。

而在文字/字符领域,这种字符与数字之间的对应关系,便是ASCII码表,和unicode码表。他们建立了字符与数字的映射关系。

计算机中只能以字节为单元的形式,存储各种数字,当然也只能处理这些数字咯。因此,有了码表,我们的程序可以写出各种算法来处理这些内存中的数字,当他们最终再按照映射关系转换为字母表达在显示器上给你看的时候,你会看到好像你的文字被处理过了。

举例来说:

1
2
3
var str = 'abc'
var replacedStr = str.replace('b', 't')
console.log(replacedStr) // 输出 'atc'

其中abc在程序解释器读入时,便成为了内存中0x61,0x62,0x63三个字节的数字值,程序继续执行做了替换操作,则出现这样的三个字节:0x61,0x74,0x63. 此时,打印时,操作系统会按照字符的码表把内存里的数字转换为文字显示在显示器上面,于是你看到了’atc’

unicode标准参考网站

unicode.org
专门的汉字对应表
这个汉字对应表的网站比较实用,当你想查看某些编码值是对应哪个文字,或者在开发中解决问题和调试的时候,可能会用到。

讲了一通,结论是什么?

结论是: 在字符处理领域,unicode码表,ASCII码表,是字符编码的基础设施。此处的这个 编码 概念,我称之为字符基础设施的映射。如果非要叫他编码,我称之为面向操作系统或字符显示设备的字符编码。

也就是说,unicode编码是面向操作系统字符显示设备来输出字符的,之所以要有unicode的编码,是因为计算机的数字总归要在终点的时候转换为字符给人看的。要通过显示器、打印机打印出来。那么数字怎么解码呢,就通过unicode表解码,显示咯。

谁来解码

字符显示设备来解码。也就是说字符显示设备的驱动,只可以认识码表中定义的这些个数字。读取这些数字,字符显示设备会将他们显示为文字图形给人来观看。

理解了这一点,我们更容易看懂下文。也就是说,除了此处的编码是为了将数学数字转换为人眼可见的图形之外,下文所讲的其实本质上跟这个数字代表a还是代表b是没有直接关系的!

面向字符解码器程序的编码: 对基础设施字符编码进行压缩的一种方式。

有了unicode,就有了现实世界与计算机数字的对应关系。 人类才可以借助计算机处理文字。

然而,人们了解unicode的码表原理之后,会发现在表达汉字等复杂字符的时候,纯unicode编码在多语言混排字符的情况下,会有空间浪费。

所以,为了字符在网络传输和存储时,减少浪费,人们希望再对unicode这种基础设置映射后的数字再做一次编码。(本质上可看做是一种压缩)

想想,”你好abc”这样的字符串,如果用unicode编码,无论存储在内存还是磁盘,每个字节都要按照2字节来存储,必然导致英文字母浪费了一个字节的空间。 所以,人们发明了UTF-8,UTF-16等的编码算法。比如UTF-8这种编码方法可以让数值比较大的字符用2到3个字节表示,数值比较小的(比如英文字母)就用一个字节来表示。

谁来解码

答: 对应编码的解码器程序。比如你utf8的文件,肯定需要一个utf8的解码器来解码(解压缩为unicode)。解码的结果是什么呢? 答: 解码的结果是unicode码。
所以顺序是这样的:
utf-8 —–> unicode ——-> 显示器上的字符图形

很显然,UTF8编码方法所表达的字节数字,是无法给计算机显示设备用的(显示设备只能解码unicode这样的码表标准上的数字)。所以UTF-8这种存储编码方法,是需要被对应的解码程序解码后再用的(比如文本编辑程序sublime,记事本,甚至用浏览器纯打开一个plaintext文本文件)。这些编辑器会利用对应编码方式的解析规则进行解码,被编辑器解码后,编辑器内存中存储的已经是解码成的unicode字节了(此处不严谨,也可能是其他形式的存在),因此显示器可以将这些人类可懂的图形显示出来。

UTF8编码规则

UTF-8之类的这种存储编码方式,必然有一些特殊的字节来标明一个字符占用几个字节(具体可参见具体编码的实现)。只有有了这些标识,文本编辑器才可以按照这些既有的规则把它们重新解码翻译成unicode这种基础设施数字。 其实这就是unicode与UTF8之间的算法转换关系了,不属于本文讨论的范畴。

图像、音视频

图像、音视频,也有对应的压缩编码方式。比如现在大家耳熟能详的png、jpg图像格式,他们都不是直接将图像的像素点依次存储在内存或磁盘上。而是用一定算法,对直接的存储方式进行了转换,减少了存储空间。 如同UTF8的实现一样,图像的存储编码方法也不属于本文范畴,暂且不表。

叫编码 还是叫 转义

在之前,我经常弄不清楚前端里面转义和编码的区别。 前端各种各样的编码、转义中,到底哪些才算编码,哪些才算转义呢?
经过这一夜的苦思冥想,我算是有点明白了,也算是我给它下的私人定义吧。

就我们本文所讨论的字符领域来说,我认为:
编码,就是上文讲到的这些。包括字符数字化的码表,以及存储方式的压缩编码。
有了编码,所有字符都有了磁盘和网络中合适的字节表示法。
在字符领域,编码解决了一个很重要的问题: 人类字符的数字化

而转义,跟底层的字符数字化是已经无关的。基础设施已经形成,转义是在利用基础设施的过程中发现有些场景下会有问题,才出现的解决方案。
比如这样一个案例: “我想在磁盘中存储一个双引号,一个tab字符,一个蜂鸣声字符, 一个中文字”. 假如使用unicode编码,则只需要把他们的unicode码点写入到磁盘上,这个任务就完成了,这是编码的功劳,可以把我们抽象的字符存储到计算机中。

于是你打开文本编辑器,输入一个双引号,输入一个tab,忽然发现蜂鸣声字符无法输入,又忽然发现电脑上没有中文输入法也无法输入中文字符。 通过键盘做不到的字符怎么办呢,因为有些字符是不可打印的比如蜂鸣声字符。 于是我们需要其他途径来告诉我们的sublime编辑器—我要输入0x07的字节到磁盘上。 此时,就涉及到一个问题: 怎么告诉sublime。
假如sublime提供了一种输入16进制进行编辑的方法,那么你就可以通过输入0x07来进行这个任务,此时sublime程序也必须认为你的输入并不是4个字符,而是要将0x07翻译成二进制存储到字节里面。

所以,转义,需要编译器或解释器程序的配合,方能读懂你要表达的字符,读懂了(知道是哪个unicode)才能正确显示、存储或传输。

OK,把sublime换成我们的编译器或者JavaScript解释器,道理是一样的。 当你的代码告诉编译器或JavaScript解释器去存储一个东西到磁盘或网络时,JavaScript解释器需要接收你给的讯息,然后存储或传输,而有些字符无法表达或者跟编译器解释器命令冲突的情况下,就必须要进行转义。本质上的目的,都是为了让解释器明白你希望表达什么字符而已。

所以,我认为在前端,JavaScript字符串中的转义、URL编码、HTML实体字符。都应该叫做 转义 。 原因在于,他们的目的都是为了让目标解释器能知晓自己所表达的字符含义,并不是让目标知道自己该如何用字节表示(那是编码机制的工作)。

转义概念: link

面向编译器or解释器的转义

转义字符可以来自任何地方。比如磁盘上,比如你输入到命令行里。
比如如下代码:

1
2
var a = 'a\tb'
fs.write(a)

当这段代码存储在磁盘上,未执行之前,每个字符都要占用磁盘空间,包括这个右斜杠,也包括这个t字母都要存储。而且在磁盘上,转义字符是无感知的,磁盘只感知到了这里有一坨代码,好多个字符(包括空格在内,包括右斜杠在内)。

当JavaScript解释器读取并执行这段代码,JavaScript解释器需要对转义有感知。因为JavaScript解释器是具有自己逻辑的程序,程序会针对一些字符做特殊处理,比如解释器认为包裹在引号里面的就是字符串, 右斜杠开头的是个转义字符,

所以,转义字符其实是给编译器或解释器程序看的。之解释器程序所以能理解转义,也是因为解释器程序里面写好了这样的逻辑—碰到右斜杠要怎样怎样…

所以理解这个转义,要区分好阶段。也就是说,我们要明白,转义发生在什么时候?你写的转义是给谁看的?代码在他被编译或执行之前,代码文件跟普通字符文件没有区别。代码被解释器读入执行分析代码语义的时候,转义字符会起作用。

谁来解转义字符

转义字符,是给编译器或解释器看的。
如:

  • JS里的字符转义,是为了给JS程序代码解释器看的。当解释器看到\u开头的以及右斜杠开头的,就认为是一个特殊的转义字符了,会按照既定的规则将他们翻译解码成真正的内存中的unicode码。

  • URL转义,是为了给WebServer端的url解释程序看的,为了避免跟url协议里特殊字符冲突,很多字符都要转义。当webserver解释器看到%开头的,便把后面的几个字符作为转义字符,然后按照转换算法一起解析为一个webserver内存里的unicode字符,ok,这下webserver也知道你传的参数到底是啥字符了。

  • HTML转义,是为了让浏览器html渲染引擎解释的时候看的。因为html解释器中尖括号都是有特殊含义的,所以尖括号这个字符又得用一种特殊的方法来表达 &lt ; 当浏览器渲染时碰到该&字符,就会把整个 < 解释为内存里的0x3c unicode码,所以能让显示器显示出小于号这个字符。而那些没被转义的尖括号,早已经被渲染引擎当做命令标签给消化掉了,不可能会显示出来的。

图像base64编码

说说图像的base64编码。其思路便是把图像的二进制表示,转换为另一种二进制表示(可反转回来)。 转换之后的二进制,每个字节都是可打印的字符,因此非常适合字符传输的网络场景。

由于这个不属于字符领域,所以可能无法套用上面所讲的分类。但他可以类比字符领域中的基础设施中的压缩编码,就是把一种数字表示法再转换为另一种数字表示法。 只不过这个base64不是为了压缩图像,而是为了更好地作为字符传输,比如放到html里(html里肯定不允许有乱七八糟的字符, 比如蜂鸣声字符之类的..)

所以base64常用在将小图嵌入到html当中。

我把图像编码归类为一种二进制的压缩编码类别。跟上文中字符的压缩编码有些类似。

总结

通过以上的分析,我们还可以得出:unicode编码以及utf-8、utf-16等压缩式编码、以及视频or图像编码,解决了现实世界的物体如何用数字存储、传输的问题。

那么,在这个基础设施的上层,人们碰到一些冲突问题,比如解释器程序需要一些字符作为代码标示,例如引号标示字符串开始结束,但代码中又有时需要表达非命令的引号,此时就需要转义。

总之,转义和编码有明确的适用场景。 转义字符在传输和存储时,仍然要借助基础设施的那些编码,在被解释器程序解释时,会根据情况解释为对应的unicode字符。

JavaScript API

JS代码中字符转义

在js字符串中,用unicode码点的十六进制方式来表达一个字符。\u
或者ES6的 \u{
}
如:

1
var a = '\u3456'

还有通过String实例函数的方法:

1
var a = String.fromCharCode(0xD834)

var a = ‘’ 这样的方式,如果引号里面字符中除了一些可以键盘输入的字符之外,其他一些特殊的字符,就得通过unicode码或者特殊的转义字符来输入了。
常用转义字符如下:

当然,所有的字符,其实都可以用过unicode码来表示出来,
比如双引号的ASC码就是 22,
所以var a= ‘\u0022’ 就是双引号
那么var b = “\”” 也是个双引号。
当然,在单引号包裹的字符串内,双引号是不需要转义的,所以双引号也可以这样: var c = ‘“‘
此时, a === b === c

然而,
JS在运行时,内存中采用类似UTF16的UCS-2编码, 所以你给个\u1234,那么他就会把这个unicode码当做UCS-2编码来实际存储这个字符。
但你搞个超过俩字节的unicode码点,js就完蛋了:

1
var a = \u1D306

这样,理论上是要给a赋值一个unicode码是1D306的字符。结果js发现实际上有3个字节,那么他就把他当成俩字符了。。。 于是js读到的第一个字符是1D30第二个字符不知道是啥了。
反正结果是 a.length 是2. 并不是1.

原因就在于: js在运行时内存中不支持可最大到4字节的UTF-16编码,而是使用的2字节的UCS-2编码。

字符集:js也是用的unicode,所以他能表示unicode中所有文字。
编码:js用的是UCS-2. 由于JavaScript只能处理UCS-2编码,造成所有字符在这门语言中都是2个字节,如果是4个字节的字符,会当作两个双字节的字符处理. 最终还是无法表达所有unicode字符咯…

所以说,js用了UNIcode,但由于编码方式,导致俩字节是无法表示全部unicode字符的。如果用UTF16就可以了,因为他可以在unicode基本平面的字符用俩字节表示,扩展平面用4字节表示。而由于目前js用的是UCS2,所以他不能像UTF16那样遇到U+D800到U+DFFF时,认为这是个4字节表示的字符。所以你假如有个字符,用UTF16要这样表示:0xD834 0xDF06
那就完蛋了。 因为js只能认为0xDB34是一个字符, 0xDF06是另一个字符。

JavaScript中的字符串操作函数也无法处理多于2个字节的码点情况: 字符串操作函数只对俩字节的unicode码点有效

1
2
3
String.prototype.replace()
String.prototype.substring()
String.prototype.slice()

因为就像length一样,你明明赋值给他一个扩展区域的Unicode码,但他当成了两个字符。

【ES6来解决】
js在ES6就采用UTF16编码方式在运行时内存表达字符了。ES6可以自动识别4字节的码点。因此,遍历字符串就简单多了
不过遍历还是得用ES6的 for item of str, 而不能用老的那些个方法。

那些prototype.replace之类的方法,为了保持兼容,也不支持ES6的UTF16字符。
必须使用UTF16特有的那些方法:

1
2
String.fromCodePoint //这个方法可以读取一个超过2字节的charcode码,生成一个字符
String.prototype.codePointAt() // 这个方法可以读取某个位置字符的unicode编码值是多少。

获取字符串的length,可以使用 Array.from(string).length。而在es6里,可以使用var a = ‘\u{1D306}’来给字符串变量赋值,就可以支持超过2个字节的码点来生成字符了。正则表达式,也需要添加上/u才能对4字节的码点提供支持。

举例:

‘𝌆’ , 该字符的unicode码是 0x1d306
有3种方式创建该字符:

1
2
3
var a = '𝌆'
var a = String.fromCodePoint(0x1d306)
var a = '\u{1d306}'

要读取a变量的这个字符的长度,需要
1
Array.from(string).length

要读取该变量第一个字符的unicode码,则:

1
a.codePointAt(0)

注意与ES5的原始方法相区别,比如对于UCS-2编码的那种字符,直接使用a.length, a.charCodeAt这些函数即可。

参考: 阮一峰字符编码笔记:ASCII,Unicode和UTF-8

HTML实体转义

由于html中,很多字符被当做特殊的含义解析,比如:< > 用于标签,& 用于转义,所以这些特殊字符如果需要让渲染引擎读取时读作普通unicode字符,则需要在源码中对他们进行转义。

另外,ASCII的字符集中不包含的字符,也需要进行转义,比如 copy版权标志,用&copy;
而ASC字符集中的其他字符,比如abcd之类的,是不需要转义的,但你也可以用其对应的ASC码十进制来表示:如&#75; 表示字母K

ASCII码表参考地址:http://www.asciitable.com/
html实体字符表:http://www.lookuptables.com/

可以发现: asc码甚至所有的unicode字符(包括中文), 都可以用&#***的方式在html里表示出来哦。只是没有必要。 而那些容易跟html本身的代码产生歧义的,比如尖括号之类的,则非常有必要进行转义。

另外,有一些特殊的字符,会在ASC码的160码点开始,定义了一些特殊的字符,如版权标志这些,详情可见:http://www.w3school.com.cn/tags/html_ref_entities.html

html转义字符表,也可以看这个工具网站:http://tool.oschina.net/commons?type=2

js代码中如何对html进行转义反转义呢?

第一种方式,利用DomAPI,因为网页上显示的东西,你用innerHTML去读,都可以读到他的源码,如果网页上显示了 <h1>那么你读innerHTML就能读到他转义后的样子。
所以,要实现转义,就让h1显示到网页上, 只需要innerText=”<h1>“,就能让页面上显示<h1>这个文本。那么,再去读他的innerHTML,读到的就是&lt;这种。
反转义,就反过来做,先innerHTML把转义后的实体字符设置到页面,这样页面上会显示这个实体字符代表的真实字符,然后在inenrText读出来。
总之,innerHTML是读写源码,innerText是读写渲染引擎解析后的。

第二种,纯js,靠正则来匹配实现。
http://www.cnblogs.com/snandy/p/3200433.html

URL转义/编码

先讲历史和背景: 一般来说,URL只能使用英文字母、阿拉伯数字和某些标点符号,不能使用其他文字和符号。比如,世界上有英文字母的网址"http://www.abc.com",但是没有希腊字母的网址"http://www.aβγ.com"(读作阿尔法-贝塔-伽玛.com)。这是因为网络标准RFC 1738做了硬性规定
(引自:http://www.ruanyifeng.com/blog/2010/02/url_encoding.html)

所以, 你网址中输入一个汉字, 或者输入其他一些乱七八糟的非RFC1738规定的字符。那么浏览器会给你自动URL编码,意思就是以RFC1738规定的那几种字符如何把你的汉字给表达出来呢?
答:就直接把汉字的二进制编码,用他16进制的字符形式表达出来。当然这样会增大空间占用,不过具有一定的可读性咯,也符合RFC规范。

RFC3986中指定了以下字符为保留字符:! * ‘ ( ) ; : @ & = + $ , / ? # [ ]
还有一些字符,当他们直接放在Url中的时候,可能会引起解析程序的歧义。这些字符被视为不安全字符,原因有很多, 如:

  • 空格:Url在传输的过程,或者用户在排版的过程,或者文本处理程序在处理Url的过程,都有可能引入无关紧要的空格,或者将那些有意义的空格给去掉。
  • 引号以及<>:引号和尖括号通常用于在普通文本中起到分隔Url的作用
  • #:通常用于表示书签或者锚点
  • %:百分号本身用作对不安全字符进行编码时使用的特殊字符,因此本身需要编码
  • {}|\^[]`~:某一些网关或者传输代理会篡改这些字符

对于Url中的合法字符,编码和不编码是等价的,但是对于上面提到的这些字符,如果不经过编码,那么它们有可能会造成Url语义的不同。因此对于Url而言,只有普通英文字符和数字,特殊字符$-_.+!*’()还有保留字符,才能出现在未经编码的Url之中。其他字符均需要经过编码之后才能出现在Url中。

但是由于历史原因,目前尚存在一些不标准的编码实现。例如对于~符号,虽然RFC3986文档规定,对于波浪符号~,不需要进行Url编码,但是还是有很多老的网关或者传输代理会进行编码。

URL编码规则:

  • Url编码通常也被称为百分号编码(Url Encoding,also known as percent-encoding),是因为它的编码方式非常简单,使用%百分号加上两位的字符——0123456789ABCDEF——代表一个字节的十六进制形式。Url编码默认使用的字符集是US-ASCII。例如a在US-ASCII码中对应的字节是0x61,那么Url编码之后得到的就是%61,我们在地址栏上输入http://g.cn/search?q=%61%62%63,实际上就等同于在google上搜索abc了。又如@符号在ASCII字符集中对应的字节为0x40,经过Url编码之后得到的是%40。

  • 对于非ASCII字符,需要使用ASCII字符集的超集进行编码得到相应的字节,然后对每个字节执行百分号编码。对于Unicode字符,RFC文档建议使用utf-8对其进行编码得到相应的字节,然后对每个字节执行百分号编码。如”中文”使用UTF-8字符集得到的字节为0xE4 0xB8 0xAD 0xE6 0x96 0x87,经过Url编码之后得到”%E4%B8%AD%E6%96%87”。

  • 如果某个字节对应着ASCII字符集中的某个非保留字符,则此字节无需使用百分号表示。例如”Url编码”,使用UTF-8编码得到的字节是0x55 0x72 0x6C 0xE7 0xBC 0x96 0xE7 0xA0 0x81,由于前三个字节对应着ASCII中的非保留字符”Url”,因此这三个字节可以用非保留字符”Url”表示。最终的Url编码可以简化成”Url%E7%BC%96%E7%A0%81” ,当然,如果你用”%55%72%6C%E7%BC%96%E7%A0%81”也是可以的。

  • 由于历史的原因,有一些Url编码实现并不完全遵循这样的原则。

我们要对提交的东西,应当尽量都进行URL编码。 确保一致性。

春节按照utf8的编码,进行url字符表达后,是这样的:%E6%98%A5%E8%8A%82
但是,这里有个表现不一致的情况,例如IE有的浏览器会用GB2312给编码,而且查询字符串里包含汉字的时候,他甚至直接把内存中的GB2312的4个字节,当做4个字符传出去了。表单提交和ajax提交时,更是不同浏览器具有不可确定性。

JavaScript几个URL编码解码的API的区别,何时用哪个?

  • escape就不用了,因为其编码方式有点过时了。

  • 而encodeURI是对整个URL编码,相当于你在浏览器里输入网址,然后回车后浏览器自动传输给服务器的效果。其中浏览器会对url中的中文部分,以及特殊字符部分进行编码,当然这并不会影响你原来的URL语义,只是方便传输而已。(而现代浏览器也不会让你看到编码后的URL,除非你打开开发人员工具)。比如你请求这个网址: http://www.baidu.com/index.php?a=1&value=a&b=1&c=你好&d=>
    实际上,浏览器是发送这样的请求出去的: http://www.baidu.com/index.php?a=1&value=a&b=1&c=%E4%BD%A0%E5%A5%BD&d=%3E

    在chrome中,可以复制浏览器地址栏里的地址,然后粘贴到另外一个地方,就可以看到真实的请求样子。
    那么,有什么用途呢? 有,在我们进行ajax异步请求时,我们应该对所有的异步请求都进行encodeURL编码,从而保证发出的请求在RFC安全字符里。
    (放心,webserver都会自动将你的中文等符号解析出来的)

  • encodeURLComponent函数,适用于传参时对参数值进行编码,避免引起URL歧义导致错误。比如如果有个queryString是 v=value=a&b=1
    其中后半段我希望都是v这个key的值,此时,就要对 value=a&b=1 这部分进行encodeURLCompounent编码。
    当然,你又不能对整个URL进行encodeURIComponent编码,否则URI规则都被破坏,你将无法发送请求。

所以遇到这样的URL,

1
var b  = 'http://www.baidu.com/index.php?a=你好&b=>&c=value&e'

且value&e是一个整体值,且需要发送异步ajax请求时:
最好这样操作:
1
2
var tmp = 'http://www.baidu.com/index.php?a=你好&b=>&c=' + encodeURIComponent('value&e')
var ajaxUrl = encodeURI(tmp)

在实际开发中,经常会需要把另外一个网址作为参数提交给服务器,这时由于网址中存在大量冲突的字符,所以你必须对这段要提交的网址进行encodeURIComponent编码后再发送这个请求!

另外,URL编码还被用在’application/x-www-form-urlencoded’这种类型的表单提交上面,同样会对你的表单内容进行URL编码。

参考: http://www.cnblogs.com/jerrysion/p/5522673.html

欢迎使用在线编解码工具

广告位 waiting