深究浏览器长整型数值精度丢失问题
alert(28443422041709109)
会输出什么?
背景
在上一篇博文里我记录了一个诡异的前后端数据不一致的问题,最终定位为前端js精度丢失。但只说了原因及结论并没有深入研究这个问题。
这一篇博文准备在此基础上,深入探寻一番,彻底弄清楚这个问题发生的本质。
引子
让我们先来看几个小问题热热身:
1 | ## js环境下运行,输出结果是什么? |
浏览器环境下运行下看看是不是有点颠覆了三观?
alert(28443422041709109)
会输出什么?
在上一篇博文里我记录了一个诡异的前后端数据不一致的问题,最终定位为前端js精度丢失。但只说了原因及结论并没有深入研究这个问题。
这一篇博文准备在此基础上,深入探寻一番,彻底弄清楚这个问题发生的本质。
让我们先来看几个小问题热热身:
1 | ## js环境下运行,输出结果是什么? |
浏览器环境下运行下看看是不是有点颠覆了三观?
今天平台在向调用的平台发送回调请求的时候,发现有问题,排查了一会儿发现并不是所有的回调请求都会有问题。基本上纯字母或数字的回调都没有问题,而出问题的请求包含”&”,”-“等特殊字符,于是第一时间想到是不是解析特殊字符的问题。
于是跟接收方约定,我将请求encode后发送,接收方接收后decode后再解析。
代码片段:
1 | var resParams = {"name":encodeURI(out.name),"blockId":blockId,"total":1,"detail":encodeURI(reportPath)}; |
发布后,重新触发,查看日志:
1 | ..."detail":"http://(绿色围墙)/detail?id=1&suffix=1438601805325"...} |
怎么貌似请求串没有改变?
第一反应,怀疑是不是编码没有成功,但我之前一直都是使用encodeURI
编码,并不会别的什么方法,于是百度了下,发现还有个encodeURIComponent以及escape的区别
方法。
1 | var resParams = {"name":encodeURIComponent(out.name),"blockId":blockId,"total":1,"detail":encodeURIComponent(reportPath)}; |
发布后,重新触发,查看日志:
1 | ..."detail":"http://(绿色围墙)/detail%3Fid%3D1%26suffix%3D1438601805325"...} |
起效了~
javascript中有三种编码的函数,分别是:*
escape()
,encodeURI()
以及encodeURIComponent()
*。
escape
该方法不对ASCII字母和数字编码,也不会对ASCII标点符号编码,除此之外的所有字符均会被编码。
基本上该方法已经被javascript标准所遗弃,从ECMAScript v3开始,标准就建议使用encodeURI和encodeURIComponent代替。
encodeURI
该方法不会对字母和数字编码,也不会对这些ASCII标点符号编码:** -_.!~*’() **
该方法的目的是对URI进行完整的编码,对URI中具有特殊含义的标点符号不进行转义。
因此正如我遇到的问题一样,如果URI中含有分隔符,则应当使用encodeURIComponent
方法编码。
encodeURIComponent
该方法不会对字母和数字编码,也不会对这些ASCII标点符号编码:** -_.!~‘() **
其他字符,如* ;/?:@&=+$,# **这些用于分隔 URI 组件的标点符号,都会由十六进制转义替换。
encodeURIComponent除了编码标准的URI之外,对于它的参数也都一并进行处理。
他们对应的解码函数分别是:unescape()
,decodeURI()
,decodeURIComponent()
#背景
在项目开发过程中,有一个需求是这样的:
平台接受用户输入的一串JSON字符,然后解析JSON串的key-value展示到平台上,并支持用户修改value值再更新。
效果图如下:
在调试过程中发现,一旦提交更新展示的字段顺序就跟前一次不一样,再提交一次更新貌似又能恢复,这是咋回事呢?
14/53,每周一篇博,坚持!
每周一篇博文的目标还是比较艰巨的,有时候时间比较紧张的时候根本来不及想主题。。
准备开一个系列,介绍下我收藏的那些小而美的JS开源库。这是第一篇,关于一个设计良好的美观实用PC、移动兼容良好的弹框库–notie。
众所周知,浏览器默认的弹框–alert是异常丑陋的,我们在业务中通常是不会直接使用alert来显示应用弹框消息的,一般都会重新设计应用自己的弹框来替代之。
notie就是一款用来替代alert的消息弹框库。
17/53,每周一篇博,坚持!
这一篇博文是小而美的库分享第二篇,准备分享一个JS键盘事件捕获的库,名字就叫做KeyPress。
我们在web开发过程中,为了给用户带来良好的用户体验,通常就不仅仅需要响应用户的鼠标操作,更多的是需要响应用户的键盘操作。通常这时候我们总是需要各种搜索查询键盘上各个按键对应的键码。
这是一个很繁琐而又没什么技术含量的事。而”KeyPress”这个库基本上就让我们摆脱了查询键码的繁琐过程,托管了我们对键盘映射的响应。
“非常容易使用,大小合理(9kb),没有任何依赖,健壮性良好的键盘输入捕获JS库”,这是KeyPress的自我评价。
18/53,每周一篇博,坚持!
今天七月一号了,不知不觉2018年又已经过去了一半了,工作后压力大感觉时间都过的快了些。想来也是,上了年纪了,现在的一年占你所剩人生的比例越来越重了,不由得让人对时间的流逝关注起来。大家都加油,与诸君共勉。
这一篇博文是小而美的库分享第三篇,准备分享一个SVG图标的库,名字叫做Vivid.js。
现如今,我们在web开发过程中,需要用到图标的时候已经很少直接插入一张图片了,更多的时候使用的都是SVG、iconfont形式的图标了。这种图标的好处就是可以自定义大小、颜色等样式。
这其中,国内有阿里开源的阿里巴巴矢量图标库,也有bootstrap之类好用的图标库。
Vivid.js也是一款优秀的矢量图标库,可以作为备选之一。
这是我转战JAVA以来的第一篇博文,纪念一下。
组织变动,转战JAVA差不多有一个月了,做了一个小需求,遇到一个诡异的问题。本文记录一下排查经过,顺便提醒自己后续开发中避免这样的坑。
JAVA后端需要给前端返回一串数据,其中有个交易订单号,该交易订单在返回给前端后跟后端吐出的值不一致。直观地来看,最后的几个数字被0取代了。
一开始以为取错了交易订单号,然而从DEBUG的过程来看,后端的处理结果没有问题,返回了正确的结果给前端。
如下图所示:
当时也并没有纠结问题的根本原因,下意识地将交易订单号类型从List<Long>
换成了List<String>
返回就正常了。
发布以后觉得这里可能是个坑,于是研究了一下果然是有缘由的。