javascript URIError: malformed URI sequence 谈谈url编码 encodeURI encodeURIComponent和escape

一、案例描述

第一个页面,url传参数给第二个页面


<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Url Encoding Demotitle>
head>
<body>
<div style="width:600px; padding: 20px; margin: 30px auto;">
	<label>物料类型:label>
	<select id="prod_type">
		<option value="成品">成品option>
		<option value="原材料">原材料option>
	select>
	<button type="button" onclick="openWindow();">打开新窗口button>
div>
body>
<script type="text/javascript">
	function openWindow() {
		var prod_type =document.getElementById("prod_type").value;
		var url = "http://localhost:8080/java-test/js-pages/urlencoding2.html?prod_type=" + escape(prod_type);
    	window.open (url, "urlencoding", 'height=600,width=800,top=80,left=100,toolbar=no,'+
    			'menubar=no,scrollbars=yes, resizable=no,location=no, status=no');
	}
script>
html>

第二个页面,url参数接收页面


<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Url Decodingtitle>
head>
<body>
<div style="width:600px; padding: 20px; margin: 30px auto;">
	<label>物料类型:label>
	<input id="prod_type" type="text">input>
div>
body>
<script type="text/javascript">
	function getParam(name) {
		var _url = window.location.href;
		if(_url.indexOf("?")>=0) {
			_url = _url.substr(_url.indexOf("?") + 1);
		}
	    var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)"); //构造一个含有目标参数的正则表达式对象
	    var r = _url.match(reg);  //匹配目标参数
	    console.log("u: ", _url);
	    if (r != null) return decodeURIComponent(r[2]); return null; //返回参数值
	};
	window.onload = function() {
		console.log("onload");
		document.getElementById("prod_type").value = getParam('prod_type');
	}
script>
html>

第二个页面在调用getParam获取参数prod_type时报错,javascript URIError: malformed URI sequence

原因分析:
第一个页面编码:escape(‘成品’),得到:%u6210%u54C1
第二个页面解码:decodeURIComponent(’%u6210%u54C1’) 所以报错了,具体原因继续往下看下文。

二、escape、encodeURI和encodeURIComponent介绍

1、escape、unescape使用说明

ECMAScript v3 反对使用该方法,应用使用 decodeURI() 和 decodeURIComponent() 替代它。
语法:
  escape(string) //必需。要被转义或编码的字符串。
返回值:
  已编码的 string 的副本。其中某些字符被替换成了十六进制的转义序列,参考w3schoo案例:

escape("Visit W3School!")	//Visit%20W3School%21
escape("?!=()#%&")		//%3F%21%3D%28%29%23%25%26
escape("http://localhost:8080/java-test/js-pages/urlencoding2*.html");
//http%3A//localhost%3A8080/java-test/js-pages/urlencoding2*.html
console.log(escape('成品'));	//%u6210%u54C1

说明:
1) 该方法不会对 ASCII 字母和数字进行编码,也不会对下面这些 ASCII 标点符号进行编码: * @ - _ + . / 。其他所有的字符都会被转义序列替换。
2)  汉字编码成unicode转移序列

2、encodeURI

语法:
  encodeURI(URIstring) //把字符串作为 URI 进行编码
返回值:
  URIstring 的副本,其中的某些字符将被十六进制的转义序列进行替换,参考w3schoo案例:

encodeURI("http://www.w3school.com.cn")	//http://www.w3school.com.cn
encodeURI("http://www.w3school.com.cn/My first/")	//http://www.w3school.com.cn/My%20first/
encodeURI("-_.!~*'()")			//-_.!~*'()
encodeURI(",/?:@&=+$#")			//,/?:@&=+$#
encodeURI('成品')			//%E6%88%90%E5%93%81
//成品 base16编码 E68890E59381

说明
1) 该方法不会对 ASCII 字母和数字进行编码,也不会对这些 ASCII 标点符号进行编码:-_.!~*’(),/?: @&=+ $ #。
2) 汉字转换成base16编码转移序列

3、encodeURIComponent

encodeURIComponent类似encodeURI,其编码生效范围更大,;/?&=+$,#也会被转成十六进制序列进行替换。

encodeURIComponent("http://www.w3school.com.cn")	//http%3A%2F%2Fwww.w3school.com.cn, :/也被编码
encodeURIComponent("http://www.w3school.com.cn/My first/")	//http%3A%2F%2Fwww.w3school.com.cn%2FMy%20first%2F,:/也被编码
encodeURIComponent("-_.!~*'()");	//-_.!~*'(),同encodeURI
encodeURIComponent(",/?:@&=+$#")	//%2C%2F%3F%3A%40%26%3D%2B%24%23
encodeURIComponent('成品')	//%E6%88%90%E5%93%81,同encodeURI

三、再此分析javascript URIError: malformed URI sequence原因

1、还原实际项目情景

  主页面为库存查询页面,可以根据仓库、物料、物料类型(成品、原材料、半成品等)、物料Tag等条件进行查询。还可以根据物料类型进一步跳转到该物料类型所有物料在不同仓库下的库存分布交叉表,横向显示不同仓库库存量,竖向为物料列表。为此需要从库存查询页面传参数:物料类型(prod_type)到物料仓库库存量交叉表查看页面。传参时由于规范没做好,没有统一使用encodeURIComponent进行编码,前端开发人员使用了escape进行编码。
  物料仓库库存量交叉表查看页面,获取url参数调用的是统一函数库使用的是decodeURIComponent进行解码,获取参数时报javascript URIError: malformed URI sequence错。

2、探究原因及如何解决

我们看下使用escape运算后的结果:
escape(‘成品’)); //%u6210%u54C1

再结合encodeURIComponent,encodeURI编码工作原理,是将某些字符转成十六进制序列,如:
encodeURIComponent(‘成品’) //%E6%88%90%E5%93%81

很明显:%u6210%u54C1,%u不是有效十六进制串,所以在执行decodeURIComponent就报javascript URIError: malformed URI sequence错啦。
那么如何解决呢?
1)获取url参数,调用的是函数库,不能把decodeURIComponent改成unescape;
2)前端开发规范,统一使用decodeURIComponent进行参数编码,好方法,但是玩意哪个开发突然短路使用了escape怎么办?

所以,还是妥协处理吧:
1)前端开发规范,统一使用decodeURIComponent进行参数编码
2)修改函数库获取url参数getPara(name),先处理要解码的字符串
%u6210%u54C1,替换成\u6210\u54C1
%25u6210%25u54C1,替换成\u6210\u54C1
然后再调用decodeURIComponent

四、附表:url常用特殊字符ascii码表

字符 十进制 十六进制 十六进制转义序列
空格 32 20 %20
! 33 21 %21
? 63 3F %3F
= 61 3D %3D
( 40 28 %28
) 41 29 %29
# 35 23 %23
% 37 25 %25
& 38 26 %26
: 58 3A %3A

你可能感兴趣的:(WEB-Front)