数据传输POST心法分享,做前端的你还解决不了这个bug?
背景
随时随地给大家提供技术支持的葡萄又来了。这次的事情是这样的,提供demo属于是常规操作,但是前两天客户突然反馈压缩传输模块抛出异常,具体情况是压缩内容传输到服务端后无法解压。
由于代码没有发生任何变动,前端相关依赖也没有升级,服务端java版本也没有变化,所以我们可以推定为环境问题;进一步仔细检查,经过反复对比后突然发现服务端收到的压缩内容变长了;和前端请求内容进行对比,发现所有的\r和\n都变成了\r\n。
综合以上分析我们初步判断:问题出在了浏览器转译之中。为了验证猜想是否正确,葡萄将chrome版本回退到92版,异常消失,服务端接收的内容也没有被替换。
问题是顺利解决了,但是Chrome POST数据内容居然会在传输过程中发生变化。一直擅长大前端技术的葡萄绝不认输,为了弄明白这一原因,我们来看看POST的细节操作到底有什么。
控制字符
首先我们需要搞清楚几个控制字符的含义。
- 回车符(CR)和换行符(LF)是文本文件用于标记换行的控制字符(control characters)或字节码(bytecode)。
- CR = Carriage Return,回车符号(\r,十六进制 ascii 码为0x0D,十进制 ascii 码为13),用于将鼠标移动到行首,并不前进至下一行。
- LF = Line Feed,换行符号( \n, 十六进制 ascii 码为 0x0A,十进制 ascii 码为10)。
紧邻的 CR 和 LF(组成 CRLF,\r\n,或十六进制 0x0D0A)将鼠标移动到下一行行首。(Windows 操作系统默认的文本换行符为 CRLF;Linux 以及 macOS 系统默认使用 LF,早期的 mac os 系统使用 CR 换行。)
在代码管理中,在不同操作系统下CRLF会有很大不同。下面在不同系统中为大家实际演示一下:
在Mac Visual Code中新建一个文档默认为LF,而Windows中为CRLF,可以选择切换行尾序列的内容的类型。
Mac版Visual Code
Windows 版
面对这种情况,需要开发者统一CRLF,以免不同操作系统开发导致代码管理的混乱。
POST传输的数据变化
弄明白了在不同系统中,控制字符会出现不同的原因,接下来我们就需要搞清楚为什么POST的数据在传输过程中发生了变化。
我们来写个简单Demo测试一下。先在页面上放一个允许换行的textarea, 输入带换行的文本,获取内容看到只有\n转译。通过FormData直接post数据到服务端,然后直接返回,看到\n全部变成了\r\n。
var uploadData = document.getElementById("ta").value
var formData = new FormData();
formData.append("data", uploadData)
fetch("http://localhost:8088/spread/getpdf", {
body: formData,
method: "POST"
}).then(resp => resp.text())
.then(text => {
console.log(JSON.stringify(text));
document.getElementById("result").innerHTML= JSON.stringify(text)
})
浏览器标识:
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.83 Safari/537.36
回退Chrome到92版本,发送和接收文本此时编为一致:
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36
深入探究这一原因,我们了解到互联网请求意见稿2046(RFC 2046)4.1.1.中有明确说明:
“ The canonical form of any MIME‘text’ subtype MUST always represent a
line break as a CRLF sequence. “
这里我们可以看到所有的文本类型都要使用CRLF,而Chrome只是修复了一个“bug”,对于用户而言,在普通文本中用户感知不到CR、LF和CRLF的区别,但是当使用场景转换到解压的文本内容就变得十分重要。
三种解决方式
大家都知道POST是HTTP的一个常用方法,而另一个我们常用的方法是GET。
关于GET和POST区别以及使用相关问题这里不做赘述,要解决POTS传输的数据变化问题,最相关的是Content-Type。
首先我们来了解Content-Type和MIME分别是什么:
Content-Type,内容类型,一般是指网页中存在的Content-Type,用于定义网络文件的类型和网页的编码,决定浏览器将以什么形式、什么编码读取这个文件,这就是经常看到一些Asp网页点击的结果却是下载到的一个文件或一张图片的原因。
在POST中常用的Content-Type有application/x-www-form-urlencoded、multipart/form-data和application/json。
1、 application/x-www-form-urlencoded
将需要内容提交表单后,内容会按照name1=value1&name2=value2的方式编码,并且key和valu e都会进行URL转码。
对于"\n"和"\r" 会被转码为'%0A'和'%0D',通过这种传输方式,避免了浏览器的对CRLF的修正可以解决以上问题。
但是这样转码会增加文本长度,原本1个字符变成了3个,结果是压缩的文本又变长了。
2、multipart/form-data
当需要想服务器提交文件时,就需要使用这种方式。前面代码中我们可以看到当formData是普通文本是会被修正,为了解决这个情况我们可以将string内容封装到Blob中作为文件流传输,来避免修正。
这样传输,服务端会以文件方式收到内容,直接读取Stream内容;对于压缩文本,这种处理方式最优。
var formData = new FormData();
formData.append("data", uploadData)
formData.append("data1", new Blob( [uploadData]))
上图展示了同样的内容,使用不同方式进行传输。
3、 application/json
Json也是目前比较流行的传输方式,json的内容在post传输中也不会被改变,如果文本内容不长,也是不错的方式。
fetch("http://localhost.charlesproxy.com:8088/spread/postjson", {
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({data: uploadData}),
method: "POST"
}).then(resp => resp.text())
.then(text => {
console.log(JSON.stringify(text));
document.getElementById("result").innerHTML= JSON.stringify(text)
})
总结
作为一个前端er,除了HTML、CSS和Javascript三大件,熟练使用Axios等类库调用API,更不可忽视的是要了解如何调试网络请求,在项目出现问题时能快速定位到问题的所在。
这里提供了在 Angular 框架下动态加载js文件时返回 Content-Type 为text/html 的Demo,大家感兴趣的可以自行下载试试。
数据传输POST心法分享,做前端的你还解决不了这个bug?的更多相关文章
- 做前端的你还没用这些软件?? out 啦
1. 编辑器 写代码只是生产软件过程中的一环.无论是数据结构.编译原理.操作系统还是组成原理都是编码的重要基础,试问没有学过编译原理的人能够针对性地进行编译优化吗?不懂操作系统的人能玩得转linux吗 ...
- 绝对精品推荐做前端的看下:Web前端开发体会十日谈
20151208感悟: 前端人的角度来看的话,感觉像是阅读一个大牛前端的全部武功的一个秘籍说明,里面的思想高价值蛋白真是太多太多,推荐看. Web前端开发体会十日谈 一直想写这篇“十日谈”,聊聊我对W ...
- zend studio 做前端推荐安装的插件
zend studio 做前端推荐安装的插件 1.Aptana插件代码提示 Zend Studio的aptana插件,解决了Zend Studio对前台代码支持不足的问题,而且在某些方面还比诸如dw优 ...
- 为什么做前端要做好SEO
我就挑干货说啦SEO可能听起来很高大上,其实翻译成中文就是"搜索引擎优化",它只是通过一定的方法在网站内外发布文章.交换连接等,最终达到某个关键词在搜索引擎上获得好的排名. 我有幸 ...
- 一个JS效果竟然要研究一天,我是不是不适合做前端?
前言 今天这篇文章的标题,显然是要搞事情.一个JS交互效果,居然花费了一天的宝贵时间才研究出来,我是不是不太适合做前端? 别急,搬好小板凳,正文从这开始- 本来今天下班回来感觉有点累,想着今天就别学了 ...
- 12个实用的 JavaScript 框架分享给前端开发者
JavaScript库是预先编写的 JavaScript 工具代码,让开发者可以更容易开发 JavaScript 应用.这个列表我们列出了2017年1月份功能丰富的 JavaScript 库,可以帮助 ...
- 做前端好还是Java好?
做前端好还是Java好?看这三方面 转载 2017年11月14日 00:00:00 1047这几年来伴随着互联网的迅速发展,新兴互联网产业的兴起,传统行业也逐渐开始互联网化,使得互联网职业在这样的背景 ...
- 从cocos2d-html5中提取出来的,用做前端开发的框架——cc.js
从cocos2d-html5中提取出来的,用做前端开发的框架——cc.js /************************************************************* ...
- php是做前端的吗?
php是做前端的吗 不是,php是后台脚本语言,由服务器执行. PHP即“超文本预处理器”,是一种通用开源脚本语言.PHP是在服务器端执行的脚本语言,与C语言类似,是常用的网站编程语言.PHP独特的语 ...
随机推荐
- 网络传输中的各种加密算法+SSL+CA证书详解
1. 数据传输分类 在互联网上数据传输有两种:明文传输和加密传输.明文传输的协议有:ftp.http.smtp.telnet.但是为了数据的完整性和安全性,所以后来引用了加密等相关手段来保证数据的安全 ...
- 入门级的Makefile制作dynamic lib
代码文件结构: . ├── dynamiclib_add.c ├── dynamiclib_mul.c ├── dynamiclibs.h ├── libs └── Makefile 1 direct ...
- VUE常见问题
VUE常见问题 对于MVVM的理解 MVVM 是 Model-View-ViewModel 的缩写 Model代表数据模型,也可以在Model中定义数据修改和操作的业务逻辑 View 代表UI 组件, ...
- 什么是 Apache Kafka?
Apache Kafka 是一个分布式发布 - 订阅消息系统.它是一个可扩展的,容错的 发布 - 订阅消息系统,它使我们能够构建分布式应用程序.这是一个 Apache 顶 级项目.Kafka 适合离线 ...
- thrift使用和源码分析
1 前言 thrift的官方文档比较差,很多细节没有介绍清楚,比如require.optional和default字段的区别是什么,为什么字段前面要写序号等,带着这些疑问,我们需要阅读生成的源码来了解 ...
- memcached 是怎么工作的?
Memcached 的神奇来自两阶段哈希(two-stage hash).Memcached 就像一 个巨大的.存储了很多<key,value>对的哈希表.通过 key,可以存储或查询任意 ...
- SpringCloud个人笔记-01-Eureka初体验
eureka是一个高可用的组件,它没有后端缓存,每一个实例注册之后需要向注册中心发送心跳,在默认情况下erureka server也是一个eureka client ,必须要指定一个 serve &l ...
- labview和matlab区别
LabVIEW和MATLAB作为本身功能比较完善的软件环境,在各自不同的领域中有着十分广泛的应用.下面小编就详细介绍LabVIEW和MATLA以及它们之间的区别. 一.LabVIEW简介 LabVIE ...
- python-成绩转换
本题要求编写程序将一个百分制成绩转换为五分制成绩.转换规则: 大于等于90分为A: 小于90且大于等于80为B: 小于80且大于等于70为C: 小于70且大于等于60为D: 小于60为E. 输入样例: ...
- 【uniapp 开发】字典工具类 ObjectUtil
{__/} ( • - •) /つ寿司 你要不要? {__/} ( • - •) /つ草莓 你要不要? {__/} ( • - •) /つ披萨 你要不要? {__/} ( • - •) /つ桃子 你要 ...