学习Node js:raw-body模块源码解析

news2024/10/7 16:19:54

raw-body是什么

raw-body的主要功能是处理HTTP请求体的原始数据。它提供了以下核心功能:

  1. 解析请求体:可以从HTTP请求中提取原始数据,包括文本和二进制数据。
  2. 配置选项:通过配置项,可以设置请求体的大小限制、编码方式等参数。
  3. 异常处理:模块能够处理异常情况,如请求体超出限制。
  4. 编码转换:支持将原始数据解码为指定编码的字符串,或者返回Buffer实例。

express中的body-parser中间件就使用了raw-body来处理请求

raw-body基础用法

安装:

npm install raw-body

引入:

var getRawBody = require('raw-body')

getRawBody函数签名如下:

getRawBody(stream, [options], [callback])

stream是需要解析的流。

options是一些配置项。

  • length - 流的长度。
  • limit - 请求体的大小限制。比如 1000'500kb''3mb'
  • encoding - 用于将请求体解码为字符串的编码。默认情况下,如果未指定编码,将返回 Buffer 实例。最有可能的是,您需要 utf-8 ,因此将 encoding 设置为 true 将解码为 utf-8

callback是解析完成之后的回调函数。

结合express一起使用的例子如下:


var contentType = require('content-type')
var express = require('express')
var getRawBody = require('raw-body')

var app = express()

app.use(function (req, res, next) {
  getRawBody(req, {
    length: req.headers['content-length'],
    limit: '1mb',
    encoding: contentType.parse(req).parameters.charset
  }, function (err, string) {
    if (err) return next(err)
    req.text = string
    next()
  })
})

// 可以在后续的express中间件中访问 req.text

也可以使用promise风格调用getRawBody

var getRawBody = require('raw-body')
var http = require('http')

var server = http.createServer(function (req, res) {
  getRawBody(req)
    .then(function (buf) {
      res.statusCode = 200
      res.end(buf.length + ' bytes submitted')
    })
    .catch(function (err) {
      res.statusCode = 500
      res.end(err.message)
    })
})

server.listen(3000)

raw-body v0.0.3源码阅读

我们选择的版本是v0.0.3,选择这个版本的原因非常简单:代码量非常少,只有70行

https://raw.githubusercontent.com/AC-greener/blog-image/main/Untitled.png

  1. 主要作用是处理一些异常,当请求体内容超过限制时会调用stream.resume这个方法销毁这个stream,防止请求数据被缓冲。
  2. 监听stream的一些事件,然后使用回调进行处理,stream之所以能调用ononceremoveListener等方法,是因为stream继承了Nodejs中的EventEmitter模块。
    1. data事件:每当可读流接收到新的数据块时,就会触发data事件。一般用于逐块处理请求体数据。
    2. end事件:end事件在可读流读取完数据后触发,表示数据流结束。
    3. error事件:当可读流发生错误时触发error事件。
    4. close事件:close事件在可读流关闭时触发,表示流已经被关闭,用于在流关闭时进行一些资源清理或收尾工作

onData

https://raw.githubusercontent.com/AC-greener/blog-image/main/20230915223514.png

onData的核心代码只有这两行:

吧收到的chunk 放到buffers数组里面,chunk的数据类型默认是Buffer类型

然后使用 chunk.length 返回当前chunk的字节数,并累加起来

onEnd

https://raw.githubusercontent.com/AC-greener/blog-image/main/20230915223614.png

onEnd的核心是57行:调用传入的回调函数,并吧Buffer.concat的结果传入

Buffer.concat方法会吧 buffers 中的所有 Buffer 实例连接在一起,返回一个新的 Buffer

cleanup

https://raw.githubusercontent.com/AC-greener/blog-image/main/20230915223806.png

cleanup中的主要逻辑就是调用removeListener对请求数据流的事件监听器进行清理,可以防止内存泄漏以及不必要的资源占用。

v0.0.3版本的代码看完之后我们再看看看v2.5.2的

raw-body v2.5.2源码阅读

2.5.2版本的代码有300多行,是0.0.3版本的四倍,不过核心功能是差不多的,差异点如下:

  • options配置项新增了encoding参数:用于吧body解码成指定编码的字符串,默认情况下,如果没有指定编码,将返回一个 Buffer 实例,
  • stream增加了aborted事件的处理:stream.on('aborted', onAborted)

raw-body依赖的模块

2.5.2版本依赖了5个npm模块

https://raw.githubusercontent.com/AC-greener/blog-image/main/20230915223839.png

先看一下这些模块的功能:

  • bytes 是一个用于在不同单位之间进行字节转换的Nodejs模块。常用方法如下:
bytes.parse('1KB');// output: 1024
bytes.format(1024);// output: '1KB'
  • http-errors 用于创建HTTP错误对象。它简化了处理HTTP请求时生成错误响应的过程。也可以和ExpressKoaConnect一起使用。用法如下:
var createError = require('http-errors')
var express = require('express')
var app = express()

app.use(function (req, res, next) {
  if (!req.user) return next(createError(401, 'Please login to view this page.'))
  next()
})
  • iconv-lite 用于处理字符编码的转换。可以在不同的字符编码之间进行转换。
const iconv = require('iconv-lite');
const originalText = '你好,世界!';

// 将文本编码为 Buffer
const encodedBuffer = iconv.encode(originalText, 'utf-8'); 

// 将编码后的 Buffer 解码为文本
const decodedText = iconv.decode(encodedBuffer, 'utf-8');
  • unpipe 用于取消可读流(Readable Stream)和可写流(Writable Stream)之间的数据传输。例如从文件读取流到HTTP响应流。unpipe 库允许你取消这种数据传输。

getRawBody是入口函数,我们一起看一下:

https://raw.githubusercontent.com/AC-greener/blog-image/main/20230915223911.png

  1. 针对参数做一些验证以及错误处理
  2. 调用bytes模块的parse方法解析传入的limit参数
  3. 调用readStream函数处理stream,这里做了判断,如果传入了回调函数,则使用回调的方式传递解析之后stream,否则使用promise风格来处理

readStream函数和v0.0.3版本的代码变化不太大:

https://raw.githubusercontent.com/AC-greener/blog-image/main/20230915224042.png

  1. 调用getDecoder函数,用于获取指定编码的解码器。而getDecoder函数里面又调用了iconv模块的getDecoder方法
  2. 监听streamaborted事件,当客户端中止 HTTP 请求时,可读流会触发 aborted 事件。比如在请求尚未完成时客户端提前关闭了连接。
    onAborted函数如下:

https://raw.githubusercontent.com/AC-greener/blog-image/main/20230915224127.png

核心逻辑就是调用createError创建一个错误信息,然后调用done函数。

done函数是readStream里面需要重点关注的函数,代码如下:

https://raw.githubusercontent.com/AC-greener/blog-image/main/20230916130346.png

1,将complete标记为true,表示这个流已经处理完了。

2,判断done函数的调用环境,如果是在同步代码块,则使用process.nextTick延迟invokeCallback函数的调用。
done函数同步调用是在这几个地方:

https://raw.githubusercontent.com/AC-greener/blog-image/main/20230915224353.png

异步调用则是在stream.on事件的几个回调函数中,并在212行标记为异步:

https://raw.githubusercontent.com/AC-greener/blog-image/main/20230915224423.png

3,根据done函数第一个参数判断是否有错误,如果有错误则调用halt方法处理streamhalt 方法会提前结束stream的读取操作。

halt函数内容如下:

https://raw.githubusercontent.com/AC-greener/blog-image/main/20230915224452.png

unpipe(stream) 会断开与这个流相关的其他管道,如果有其他流正在处理 stream 输出的数据,这些流不会收到来自 stream 的数据。

pause 方法是 Nodejs 可读流的一个方法,用于将流暂停,停止触发 data 事件,不再传递数据。

总结

本文我们了解了raw-body的简单使用,raw-body模块也是Nodejs生态中使用的很频繁的一个模块,通过对v0.0.3和v2.5.2版本源码的解析,也了解了内部实现。

参考资料

https://github.com/stream-utils/raw-body

https://nodejs.cn/dist/latest-v18.x/docs/api/stream.html

https://nodejs.cn/dist/latest-v18.x/docs/api/buffer.html
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1017527.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

主题教育活动知识竞赛小程序界面分享

主题教育活动知识竞赛小程序界面分享

Git - Git 工作流程

文章目录 Git WorkFlow图解小结 Git WorkFlow Git Flow是一种基于Git的工作流程,确实利用了Git作为分布式版本控制系统的优势。 本地代码库 (Local Repository): 每个开发者都维护自己的本地代码库,这是Git分布式性质的体现。本地代码库包含了完整的项目…

清华发力了,EUV光刻机技术取得重大突破,外媒:没想到如此快

日前媒体纷纷传言清华研发成功EUV光刻机,这个其实夸大了事实,不过却也确实是EUV光刻机的重大突破,将绕开ASML等西方垄断的EUV光刻技术路线,开辟一条全新的道路。 据了解清华研发成功的并非是EUV光刻机,而是可用于EUV光…

输入M*N阶矩阵A和B,用函数编程计算并输出A与B之和

#include<stdio.h> #define M 2 #define N 3 void scanfjuzhen(int arr[M][N])//向二维数组输入数据 {int i 0;int j 0;for (i 0; i < M; i){for (j 0; j < N; j)scanf("%d", &arr[i][j]);} } void sumjuzhen(int a[M][N], int b[M][N],int c[M]…

性能测试 —— Jmeter 常用三种定时器

1、同步定时器 位置&#xff1a;HTTP请求->定时器->Synchronizing Timer 当需要进行大量用户的并发测试时&#xff0c;为了让用户能真正的同时执行&#xff0c;添加同步定时器&#xff0c;用户阻塞线程&#xff0c;知道线程数达到预先配置的数值&#xff0c;才开始执行…

Rust踩雷笔记(7)——一个链表题例子初识裸指针

题目在这https://leetcode.cn/problems/palindrome-linked-list/&#xff0c;leetcode 234的回文链表&#xff0c;思路很简单&#xff0c;就是fast和slow两个指针&#xff0c;fast一次移动两个、slow一次一个&#xff0c;最后slow指向的链表反转后和head比较就行了。 很简单一…

趣解设计模式之《新娘到底叫啥名啊?》

〇、小故事 前一段时间&#xff0c;在网上流传了这么一段视频&#xff0c;视频是一对新人的婚礼现场&#xff0c;主持人让新郎当着众多亲戚朋友的面&#xff0c;大声对新娘表达自己的爱意&#xff0c;小伙子自信满满大声的对众人说&#xff1a;“我爱你&#xff0c;周秀楠&…

ddns有什么作用?无公网IP怎么将内网IP端口映射外网访问

DDNS是什么&#xff1f; DDNS英文全称Dynamic Domain Name Server&#xff0c;中文含义是指动态域名服务。很多普通路由器或者智能路由器设置中&#xff0c;都可以找到DDNS&#xff08;动态DNS&#xff09;功能。 上面的解释可能过于专业&#xff0c;其实DDNS通俗点说&#xf…

Alpaca构建方式探秘:低成本构造指令数据增强LLM

原博客地址&#xff1a;Alpaca: A Strong, Replicable Instruction-Following Model github地址&#xff1a;https://github.com/tatsu-lab/stanford_alpaca Alpaca简介 Alpaca是斯坦福大学在Meta开源的大模型LLaMA 7B基础上使用自构建的52K指令数据重新训练得到的增强模型&am…

Android Studioc打印+查看日志

目录 Logcat 写入日志 查看应用日志 Logcat 写入日志 错误&#xff1a;Log.e(String, String)警告&#xff1a;Log.w(String, String)信息&#xff1a;Log.i(String, String)调试&#xff1a;Log.d(String, String)详细程度&#xff1a;Log.v(String, String) 查看应用日志 …

IT老齐的Redis 6实战课

NoSQL与Redis6新特性 什么是Redis REDIS一个开源的使用 ANSI C 语言编写、遵守 BSD 协议、支持网络、可基于内存、分布式、可选持久性的键值对(Key-Value)存储数据库&#xff0c;并提供多种语言的 APIRedis的读写性能非常好,官方压测数据为 Redis能读的速度是110000次/s,写的…

【MySQL系列】MySQL的用户管理

「前言」文章内容大致是MySQL的用户管理。 「归属专栏」MySQL 「主页链接」个人主页 「笔者」枫叶先生(fy) 目录 一、用户管理1.1 用户信息1.2 创建新用户1.3 删除用户1.4 修改用户密码 二、数据库的权限2.1 给用户授权2.2 回收用户权限 一、用户管理 MySQL与Linux类似&#x…

图形学线性代数

最近学图形学&#xff01;学的是GAMES101-现代计算机图形学入门-闫令琪↓会做点笔记 Lecture 03 Transformation_哔哩哔哩_bilibili 点乘 1&#xff09;主要作用是找到两个方向/向量的夹角 2&#xff09;找一个向量投影到另一个向量 作用 叉乘 此处x,y,z都是坐标轴 作用 1&a…

HTML+CSS画一个卡通中秋月饼

HTMLCSS画一个卡通中秋月饼&#x1f96e;&#x1f96e;&#x1f96e; 中秋活动水个文章 整个divcss实现个月饼&#xff0c;给前端初学者一个练手的demo 效果图 思路 HTMl 先来个轮廓画脸上的东西&#xff1a;眼睛、眉毛、腮红、嘴巴眼睛丰富下瞳孔画20个花瓣 CSS 轮廓是要外…

4G版本云音响设置教程腾讯云平台版本

文章目录 4G本云音响设置教程介绍一、申请设备三元素1.腾讯云物联网平台2.创建产品3.设置产品参数4.添加设备5.获取三元素 二、设置设备三元素1.打开MQTTConfigTools2.计算MQTT参数3.使用USB连接设备4.设置参数 三、腾讯云物联网套件协议使用说明1.推送协议信息2.topic规则说明…

WebGL 根据模型矩阵的逆转置矩阵计算运动物体的光照效果

目录 前言 坐标变换引起法向量变化 变化规律&#xff1a; 魔法矩阵&#xff1a;逆转置矩阵 逆转置矩阵的用法总结 Matrix4对象的 setInverseOf 、transpose 方法规范&#xff08;以完成逆转置矩阵&#xff09; 示例代码&#xff08;LightedTranslatedRotatedCube.js&am…

虚拟机Ubuntu操作系统常用终端命令(2)(详细解释+详细演示)

本篇概要 本篇讲述了Ubuntu操作系统常用的几个功能&#xff0c;即超级用户&#xff0c;虚拟机系统损坏如何修复&#xff0c;用户和组&#xff0c;如何以root登录界面以及文件的权限方面的知识。希望能够得到大家的支持。 文章目录 本篇概要1.超级用户1.1使用超级用户1.2切换到…

【ICer必备基础】MOS电容——电容电压特性详解

【ICer必备基础】MOS电容——电容电压特性详解 1相关定义2MOS电容描述3MOS电容能带分析4可变电容实际应用 1相关定义 MOS电容是集成电路中非常重要的应用&#xff0c;器件电容的定义为&#xff1a; 阈值反型点&#xff1a; 当达到最大耗尽宽度且反型层电荷密度为零时的情形。此…

在Windows上无法使用TortoiseSVN等工具管理WSL2中的代码的问题

环境 Windows 11 WSL2&#xff08;Ubuntu 22.04&#xff09; 前言 众所周知&#xff0c;WSL2 的跨系统IO读写性能非常差&#xff08;详情见我之前写的这篇文章&#xff09;&#xff0c;而我的代码又是在 WSL2 中运行的&#xff0c;为了提高性能&#xff0c;所以我的代码也必…

2023 Google 开发者大会:无障碍游戏体验升级、安卓开发人员生产力爆棚

目录 前言 一、会说话的狗 - “大黄” 二、GameFace -联合《荒野行动》&#xff0c;提升无障碍游戏体验 三、Android Studio Bot-解放开发人员生产力 五、Purnima致中国开发者的一封“信” 结语 &#x1f388;个人主页&#xff1a;库库的里昂 &#x1f390;CSDN新晋作者 …