我们都知道javascript在做表单提交的时候,会遇到很多坑爹的 中文需要转换成gbk encode或者big5 encode的问题,
比如 中文的 javascript原生的escape只是将中文转换为unicode编码,encodeURI或者encodeURIComponent也是对于中文unicode编码的url再编码
对于“中文”这个汉字来说,他的utf-8的urlencode是%E4%B8%AD%E6%96%87
,而gbk的urlencode是%D6%D0%CE%C4
而js本身没有特性支持gbk的urlencode,大部分的时候我们是通过后台(java,urlencode.encode(“中文”,”gbk”))这样来实现的
本文介绍一个借助浏览器,纯前端实现各种编码集的urlencode方式和decode方法
demo地址:http://xueduany.github.io/KitJs/urlencode.html,(这个包含了 解码,编码方法)
http://xueduany.github.io/KitJs/getEncodeStr.html(这个用来iframe回调解码后的值的文件)
chrome,firefox,safari测试通过,移动端均可,IE10以下下面会另说
(一) 编码原理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | function urlencode(str, charset, callback) { //创建form通过accept-charset做encode var form = document.createElement('form'); form.method = 'get'; form.style.display = 'none'; form.acceptCharset = charset; var input = document.createElement('input'); input.type = 'hidden'; input.name = 'str'; input.value = str; form.appendChild(input); form.target = '_urlEncode_iframe_'; document.body.appendChild(form); //隐藏iframe截获提交的字符串 if (!window['_urlEncode_iframe_']) { var iframe = document.createElement('iframe'); //iframe.name = '_urlEncode_iframe_'; iframe.setAttribute('name', '_urlEncode_iframe_'); iframe.style.display = 'none'; iframe.width = "0"; iframe.height = "0"; iframe.scrolling = "no"; iframe.allowtransparency = "true"; iframe.frameborder = "0"; iframe.src = 'about:blank'; document.body.appendChild(iframe); } // window._urlEncode_iframe_callback = callback; //设置回调编码页面的地址,这里需要用户修改 form.action = 'getEncodeStr.html'; form.submit(); setTimeout(function() { form.parentNode.removeChild(form); iframe.parentNode.removeChild(iframe); }, 500) } |
通过HTML元素form自带属性accept-charset在表单提交发送数据时候,浏览器会根据这个属性值做自动urlencode,get/post方式均可
accept-charset 属性规定服务器处理表单数据所接受的字符集。
accept-charset 属性允许您指定一系列字符集,服务器必须支持这些字符集,从而得以正确解释表单中的数据。
该属性的值是用引号包含字符集名称列表。如果可接受字符集与用户所使用的字符集不相匹配的话,浏览器可以选择忽略表单或是将该表单区别对待。
浏览器支持
除了 Internet Explorer,accept-charset 属性得到几乎所有浏览器的支持。
注释:accept-charset 属性无法在 Internet Explorer 中正确地工作。如果 accept-charset 属性设置为 “ISO-8859-1″,IE 将发送以 “Windows-1252” 编码的数据。
语法
1 | <form accept-charset="value"> |
从例子的代码,我们巧妙的利用了这个属性,构造一个接受gbk encode之后url的页面,通过location.search获取到encode之后的编码,再传递给原页面,即可实现对于任意字符的任意编码urlencode
(二)解码
上面说了编码,现在说说 如果我们获得一串%D6%D0%CE%C4,而且我们知道这个是gbk编码的,那么我们如何得到这个编码的中文呢?
1 2 3 4 5 6 7 8 9 | function urldecode(str, charset, callback) { window._urlDecodeFn_ = callback; var script = document.createElement('script'); script.id = '_urlDecodeFn_'; var src = 'data:text/javascript;charset=' + charset + ',_urlDecodeFn_("' + str + '");' src += 'document.getElementById("_urlDecodeFn_").parentNode.removeChild(document.getElementById("_urlDecodeFn_"));'; script.src = src; document.body.appendChild(script); } |
这个问题的核心在于编码是urlencdoe的,那么除了utf-8格式的我们可以借助js自己的decodeURI等之后,对于gbk的,我们一般是无能为力的
这里巧妙构造了一个URI资源,因为通过URI方式引入的script,可以指定字符编码的,而浏览器会根据指定的字符编码,做urldecode,这样就实现了我们想要的urldecode效果
(三)IE
最后,我们来看看比较郁闷的IE,对于IE来说,他完全不认我们的form的accept-charset属性,他们的表单提交的编码格式,是按照页面的meta制定的字符集来的,当然了,他也给广大屌丝前端留了一条后路,就是他们的document.charset属性,是可读可写的,
而且IE为了表现它确实是一傻到底,不但在设置document.charset的时候不会用新的编码解释页面,还会在前进后退(我特地用#作为action来实现后退)的时候又尝试用新的编码去解释页面。
所以我们需要hook之前的编码,在解码后再转换回来
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | function urlencode(str, charset, callback) { //创建form通过accept-charset做encode var form = document.createElement('form'); form.method = 'get'; form.style.display = 'none'; form.acceptCharset = charset; if (document.all) { //如果是IE那么就调用document.charset方法 window.oldCharset = document.charset; document.charset = charset; } var input = document.createElement('input'); input.type = 'hidden'; input.name = 'str'; input.value = str; form.appendChild(input); form.target = '_urlEncode_iframe_'; document.body.appendChild(form); //隐藏iframe截获提交的字符串 if (!window['_urlEncode_iframe_']) { var iframe = document.createElement('iframe'); //iframe.name = '_urlEncode_iframe_'; iframe.setAttribute('name', '_urlEncode_iframe_'); iframe.style.display = 'none'; iframe.width = "0"; iframe.height = "0"; iframe.scrolling = "no"; iframe.allowtransparency = "true"; iframe.frameborder = "0"; iframe.src = 'about:blank'; document.body.appendChild(iframe); } // window._urlEncode_iframe_callback = function(str) { callback(str); if (document.all) { document.charset = window.oldCharset; } } //设置回调编码页面的地址,这里需要用户修改 form.action = 'getEncodeStr.html'; form.submit(); setTimeout(function() { form.parentNode.removeChild(form); iframe.parentNode.removeChild(iframe); }, 500) } function urldecode(str, charset, callback) { var script = document.createElement('script'); script.id = '_urlDecodeFn_'; window._urlDecodeFn_ = callback; if (document.all) { //隐藏iframe截获提交的字符串 if (!window['_urlDecode_iframe_']) { var iframe = document.createElement('iframe'); //iframe.name = '_urlDecode_iframe_'; iframe.setAttribute('name', '_urlDecode_iframe_'); iframe.style.display = 'none'; iframe.width = "0"; iframe.height = "0"; iframe.scrolling = "no"; iframe.allowtransparency = "true"; iframe.frameborder = "0"; iframe.src = 'about:blank'; document.body.appendChild(iframe); } //ie下需要指明charset,然后src=datauri才可以 iframe.contentWindow.document.write('<html><scrip src="data:text/javascript;charset=gbk,parent._decodeStr_=\'' + str + '\'" charset="gbk" ?t + ?></S'+'CRIPT>'); setTimeout(function() { callback(_decodeStr_); iframe.parentNode.removeChild(iframe); }, 300) } else { var src = 'data:text/javascript;charset=' + charset + ',_urlDecodeFn_("' + str + '");'; src += 'document.getElementById("_urlDecodeFn_").parentNode.removeChild(document.getElementById("_urlDecodeFn_"));'; script.src = src; document.body.appendChild(script); } } |
关键点在于,编码时
解码时的关键在与,对于支持datauri版本的ie,不仅仅在于datauri里面制定编码集,还在在script的charset上指定编码
这样就可以实现浏览器的完美兼容
(四)小结
再次感谢腾讯前端QQ群的各位,没有你们的建议和支持,不会想到这么好的解决方案,再次感谢大家,希望看到的广大的前端屌丝们大力扩散,早日每一个jser都知道这一特大喜讯!!!哈哈哈哈哈
程序源代码地址:
https://github.com/xueduany/KitJs/blob/gh-pages/urlencode.html
https://github.com/xueduany/KitJs/blob/gh-pages/getEncodeStr.html
转载自:http://www.cnblogs.com/xueduanyang/archive/2013/05/30/3108442.html
回去看了下原文,排版之乱,毫无继续阅读的兴致,且不论没有代码高亮,至少也得让代码显得和其它文字不一样吧,加个背景色可以吧?然后图片缩放也是乱七八糟。cnblogs的文章几乎都是这样子的,不过文章质量挺高。
感谢支持,转载的时候的确要整理一番~
你好,能采取不回调的方式,实现解码的功能吗
这个文章里的方法是做不到了,可以考虑做一个转换的接口,ajax来获取
引用通告: URL编码详解与DOM中GBK编码实践 - 技术 - 爱好博客
热烈鼓掌,很好的解决了一些问题