问题描述
2017年09月13日,客服反馈:用户从官网根据条件筛选导出记账数据的excel文件为空,没有任何记录。但是,在官网根据相同的条件过滤是可以查到对应的流水记录的。
问题分析
通过拿到用户的账号登录进去,利用chrome浏览器,F12打开调试模式,按照用户输入的流水过滤条件,备注含“中交5#905”的参数进行过滤,在列表页确实可以查到对应的流水记录,然后,试着导出数据,发现并没有报错,但是excel无记录,通过排查导出请求的参数,意外的发现,我输入的过滤条件“中交5#905”,却变成了“中交5”。起初以为是我们定义的js做了特殊的过滤什么的处理,但是通过一步步的浏览器端调试,并没有发现这样的逻辑,通过逐步缩小范围,最终发现是浏览器搞的鬼,它会自动将URL查询字符串中#号后面的字符串截掉,仅将前面的发给服务端,例如:http://www.pandan.xyz/api/info?key1=xxx&key2=中交5#905&key3=value3,最后浏览器发送给服务端的,URL则变成了http://www.pandan.xyz/api/info?key1=xxx&key2=中交5,导致后续的过滤到的流水记录为空。
而列表页之所以可以查询出来,因为是采用ajax提交的请求参数信息,不存在参数截断丢失的问题。
那么,是什么原因会导致浏览器会截断URL查询字符串#之后的参数信息呢?通过在google了解到,原来http协议中有一些字符,是具有特殊的含义的。
- ‘?’ 用于分隔uri和查询字符串queryString
- ‘=’ 用于分隔key=value
- ‘&’ 用于分隔多参数key1=value1&key2=value2
- ‘#’ 用于标记锚点
- ‘/‘ 用于分隔uri目录层级/api/info
- ‘+’ 服务器解码之后,拿到的是空格,会存在冲突
- ‘%’ 很多字段编码之后会含有%,例如中文编码之后,都会含有%28什么的,也存在冲突
而其中#在URL中是表示锚点用的,例如http://www.pandan.xyz/api/info?key1=xxx&key2=中交5#905&key3=value3
,905&key3=value3表明页面的锚点标记,浏览器会自动定位到此页面此标记位置处。所以浏览器自动截断了#之后的参数信息,没有传给服务器,因为服务器不需要这些数据。
解决办法
在上面分析了问题产生的原因,那么如何去解决URL查询字符串中,用户输入的参数值中含http特殊字符导致请求无效呢?答案是对URL查询字符串中,参数值进行转义后在传输。利用浏览器自带的encodeURIComponent进行编码或者采用其他的编码之后在传输,例如Base64, Urlencode等,查询字符串中的参数值千万不要直接传输,因为你不知道用户会输入哪些字符,很有可能就会导致上述问题,或者服务器响应400错误,即请求无法解析,格式不合法。
key2=中交5#905 ——> key2=encodeURIComponent(“中交5#905”);
参考链接