乐趣区

关于前端:数据传输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,大家感兴趣的能够自行下载试试。

Demo 地址:https://gcdn.grapecity.com.cn…

退出移动版