第四章 请求的“附件”
email 的附件功能很好用, 附件可能是一个超级大的文件, 但不必等附件下载完毕,而可以先阅读文本部分。 甚至我们发现附件没什么用时,干脆不下载,节省时间、流量。
假设没有附件的这种机制:
email 在附件接收完毕前,
连是谁发来的都不知道,
那会怎样?
可能下载了半天,才能打开邮件,最后发现只是一个垃圾广告,甚至是有害信息。
在 http 通信中,也有这种机制。 http 通信中,数据分为两部分:header 和 body。 上上一章(收信、回信)中读取的 host、method、path 都在 header 里。 这一章介绍 “如何读取 http body”。
一般地,以下几种情况,会把数据放在 body,而不是 header 里:
- 发送 json 数据
- 发送 form 数据
- 文件上传
读 body
客户端发送的 body,可能很大, 因此后端在处理 body 时, 会在收到 “一小段” 数据后,就立刻交给我们处理。 看下面的代码你就明白了:
第 4-6 行,添加了一个监听器:每收到一小段数据时,就执行第 5 行。 数据量大时,会被分为很多段,以便尽早处理已经收到的数据,因此第 5 行可能会执行多次。
第 7-11 行,添加了另一个监听器:body 接收完毕时,执行 8-10 行。 因为 “完毕” 只有一次,所以第 8-10 行,只执行一次。
尽管上面的代码没有实际用途, 但是用最少的代码展示了 Node.js 读取 body 的机制。 下面读 json 的案例,尽管更实用一些,但不过只是技术细节,并不重要。
读 body 里的 json 数据
客户端往往这样发送 json:
这里又碰到了
Content-Type
。实际上是非必需的,但有些库会读取Content-Type
,自动解析 body。
axios 发送 json 时,当然也不例外。但 axios 封装程度较高,隐藏了一些细节,所以不好直接从代码观察。
在后端,只要把收到的所有 “一小段” 们拼接在一起就可以了:
而大多数 json 数据并不大,
所以 req.on('data', chunk => ...)
很多时候只执行一次。
封装 read_json 函数
可以把读取 json 的代码,写在一个函数里:
另外还有两种异常:
- 数据传输过程中出现异常(比如传输中断)
- 数据解析时出现异常(非法 json)
于是可以给 read_json 加上异常处理代码: