数据传输 POST 心法分享,做前端的你还解决不了这个 bug?

2022-04-20 13:47:56 +08:00
 GrapeCityChina

背景

随时随地给大家提供技术支持的葡萄又来了。这次的事情是这样的,提供 demo 属于是常规操作,但是前两天客户突然反馈压缩传输模块抛出异常,具体情况是压缩内容传输到服务端后无法解压。

由于代码没有发生任何变动,前端相关依赖也没有升级,服务端 java 版本也没有变化,所以我们可以推定为环境问题;进一步仔细检查,经过反复对比后突然发现服务端收到的压缩内容变长了;和前端请求内容进行对比,发现所有的\r 和\n 都变成了\r\n 。

综合以上分析我们初步判断:问题出在了浏览器转译之中。为了验证猜想是否正确,葡萄将 chrome 版本回退到 92 版,异常消失,服务端接收的内容也没有被替换。

问题是顺利解决了,但是 Chrome POST 数据内容居然会在传输过程中发生变化。一直擅长大前端技术的葡萄绝不认输,为了弄明白这一原因,我们来看看 POST 的细节操作到底有什么。 控制字符 首先我们需要搞清楚几个控制字符的含义。

在代码管理中,在不同操作系统下 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/forum.php?mod=attachment&aid=NDc5OTJ8YmU1Mjk0NDN8MTY1MDI2MTI0M3wxfDUwOTgw

609 次点击
所在节点    推广
0 条回复

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/848124

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX