浅析Node.js中http代理的实现

文章目录

    • 前言
    • `ReadableStream`和`WritableStream`
    • `req.pipe`
    • 小结

前言

起因是狼书卷1中的API Proxy例子,代码如下:

const http = require('http')
const fs = require('fs')const app = http.createServer((req, res) => {if ('/remote' === req.url) {res.writeHead(200, { 'Content-Type': 'text/plain' })return res.end('Hello remote page!\n')} else {proxy(req, res)}
})function proxy(req, res) {const options = {host: req.host,port: 3000,path: 'remote',method: req.method, //原文是GETheaders: req.headers,agent: false}let httpProxy = http.request(options, (response) => {response.pipe(res)})req.pipe(httpProxy)
}app.listen(3000, function () {const PORT = app.address().portconsole.log(`Server running at http://127.0.0.1:${PORT}/}`)
})

例子没有什么问题,很好的实现了一个简单的http代理. 但读代码的过程中,还是发现了一些可以略做深究的点,记录如下。

ReadableStreamWritableStream

我们从代码说起,这个proxy的核心方法是:

function proxy(req, res) {const options = {host: req.host,port: 3000,path: 'remote',method: req.method, //原文是GETheaders: req.headers,agent: false}let httpProxy = http.request(options, (response) => {response.pipe(res)})req.pipe(httpProxy)
}

这个方法中,创建了转发请求需要的options, 其中包含目标服务器的信息,请求地址,以及请求头headers.
proxy方法的两个参数分别是req,res. req是一个Readable Streamres是一个Writable Stream. 这里要注意,readable还是writable是在server的角度来看的:server需要从req中读取请求信息,把返回的内容写入到res中.

在整个代理的过程中,依靠的是pipe来连接,pipe实现的功能是连接Readable StreamWritable Stream,反之亦然.
reqres的读写属性我们刚才分析了,现在来看httpProxy和方法回调中的response,但是这时,要从client角度来看了,response是远程服务返回的信息,是一个ReadableStream. httpProxyhttp.request返回的值,类型是http.ClientRequest, 继承自OutgoingMessage,也是一个Writable stream.

我们整理一下

ObjectRead/Write
reqReadable
resWritable
httpProxyWritable
responseReadable

到这里,流程非常清楚了

req(readable) ⇒ httpProxy(writable)
response(readable) ⇒ res(writable)

整个代理的流程厘清了.

req.pipe

读代码的时候,还想到了一个问题, httpProxy = http.request 这一行,不是已经发起请求吗, 为什么最后还要req.pipe?

这里涉及到http.request的请求过程,在调用这个方法的时候,实际上只是发出了请求头,此时并不能认为这个请求已经完成,例如POST请求就可能会要写入其它的数据到stream中。所以,这里req.pipe是将原始请求的流定向到了代理请求中,确保所有数据都写入。

用一个简单的例子就能看清楚

const http = require('http');// POST 请求选项
const options = {hostname: 'www.example.com',port: 80,path: '/submit-form',method: 'POST',headers: {'Content-Type': 'application/x-www-form-urlencoded'}
};// 发送POST请求
const req = http.request(options, (res) => {let data = '';res.on('data', (chunk) => {data += chunk;});res.on('end', () => {console.log(data);});
});// 发送请求数据
req.write('key1=value1&key2=value2');
req.end();

例子中,req 就要通过write 进行请求数据的写入.

所以req.pipe 是必须的,因为需要保证请求的stream中所有数据被转发.

小结

本文简单分析了Node.js实现proxy的一些容易忽略的知识点,涉及可读可写流,以及http请求的发起过程. 欢迎交流。

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

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

相关文章

canal 服务安装

简介:Canal 是阿里巴巴开源的一个基于 MySQL 数据库增量日志解析的中间件,用于提供准实时的数据同步功能。 准备工作 1.修改配置文件 ,需要先开启 Binlog 写入功能,配置 binlog-format 为 ROW 模式,my.cnf 中配置如下&#xf…

五种实用方法!手把手教你系统盘瘦身

随着电脑的使用时间变长,电脑硬盘会逐渐被各种类型的数据占满,其中系统盘的可用空间也在慢慢变小。这是因为系统在运行过程中会产生大量临时文件和缓存文件,同时,系统的每一次更新升级也都会生成相关的文件夹存放在系统盘中&#…

LeetCode题练习与总结:克隆图--133

一、题目描述 给你无向 连通 图中一个节点的引用,请你返回该图的 深拷贝(克隆)。 图中的每个节点都包含它的值 val(int) 和其邻居的列表(list[Node])。 class Node {public int val;public L…

阐述一下Golang中defer的原理

基本用法 在Go语言中,defer关键字用于在函数返回前执行一段代码或调用一个清理函数。这对于处理文件关闭、解锁或者返回一些资源到资源池等操作非常有用。 其基本用法如下所示: package mainimport "fmt"func main() {example() }func exam…

如何使用Rekono结合多种工具自动完成渗透测试

关于Rekono Rekono是一款功能强大的自动化渗透测试工具,该工具能够结合其他多种网络安全工具并以自动化的形式完成整个渗透测试过程。在工具运行的过程中所收集到的数据将通过电子邮件或Telegram同时发送给用户,如果需要更加高级的漏洞管理功能&#xf…

浏览器(Browser):轻量级浏览器,高效浏览新体验

在可的哥桌面(Codigger Desktop),我们始终秉持创新精神,致力于提供卓越的用户体验。如今,我们激动地宣布一项全新功能的发布——轻量级浏览器Browser。这款浏览器的推出,正是我们对用户体验追求的再次体现&…

设施布置之车间布局优化SLP分析

一 物流分析(Flow Analysis) 的基本方法 1、当物料移动是工艺过程的主要部分时,物流分析就是工厂布置设计的核心工作,也是物料搬运分析的开始。 2、零部件物流是该部件在工厂内移动时所走过的路线, 物流分析不仅要考虑…

智慧水务十大预测

智慧水务是指利用现代信息技术,如物联网(IoT)、大数据、云计算、人工智能(AI)等,对水务系统进行智能化改造和管理,以提高水资源的利用效率、保障供水安全、降低运营成本和环境影响。以下是对智慧水务未来发展的十大预测: 数字化转…

免费ai写作?这三款软件是你的好帮手!

在信息爆炸的今天,自媒体已成为越来越多人展现自我、分享知识的平台。然而,对于许多自媒体创作者来说,写作过程中的灵感枯竭、文笔不畅等问题常常困扰着他们。幸运的是,随着人工智能技术的飞速发展,免费AI写作软件应运…

小程序onLoad 和 onShow

onLoad 和 onShow 是小程序页面的生命周期函数,它们在不同的时机触发,具有不同的用途和执行顺序 1.onLoad: (1)onLoad 在页面加载时触发,仅执行一次。 (2)用于页面的初始化操作,例如…

2024全国高校名单发布,电子版下载!

今天,教育部网站发布了《全国高等学校名单》。截至2024年6月20日,全国高等学校共计3117所,其中:普通高等学校2868所,含本科学校1308所、高职(专科)学校1560所;成人高等学校249所。本…

java试卷练习1

试卷练习1 一、单项选择题。 在每小题列出的四个备选项中只有一个选项是符合目的要求的,请将其代码填写在 题后的括号内。 1、Java 语言中,byte 类型占用的二进制位数是:(D) A、1 位 B、2 位 C、4 位 D、8 位 解释…

任务4.8.3 利用SparkSQL统计每日新增用户

实战概述:利用SparkSQL统计每日新增用户 任务背景 在大数据时代,快速准确地统计每日新增用户是数据分析和业务决策的重要部分。本任务旨在使用Apache SparkSQL处理用户访问历史数据,以统计每日新增用户数量。 任务目标 处理用户访问历史数…

简单了解雪花算法

雪花算法是什么 不多解释。看一看 具体是怎么 生产 唯一ID 的。 ID 由多个数据组合拼接成64位,分别是 时间戳 服务器节点ID 序列号,每个数据项占的位数不固定,可以根据实际需求设置。首位 1 个二进制位 是 符号位。 public long allocate(l…

数字样机:飞行器状态控制系统仿真

引言:数字样机起源于20世纪90年代,是一种用数字化模型代替实际物理样机进行仿真分析的技术。 传统的飞行器研发流程往往遵循一套特定的循环结构:在设计初期,工程人员需要对飞行器提供一个综合的设计思路(初期蓝图&…

“河南省勘察设计资质整合趋势与企业应对“

"河南省勘察设计资质整合趋势与企业应对" 河南省勘察设计资质的整合趋势与企业应对策略可以从以下几个方面来分析: 整合趋势: 资质标准简化与合并:随着国家和地方政府深化“放管服”改革,勘察设计资质的管理趋向简化&…

Linux【实操篇-文件目录类命令】

05【实操篇-文件目录类命令】 1.pwd 显示当前工作目录的绝对路径 pwd:print working directory 打印工作目录 到现在为止,我们还不知道自己在系统的什么地方。在浏览器上,我们能够通过导航栏上的url,了解到自己在互联网上的具体坐标。相似的…

Linux权限理解

目录 一.权限的概念 二.Linux权限管理 1.文件访问者的分类(人) 2.文件类型和访问权限(事物属性) 3.文件权限值的表示方法 4.文件访问权限的相关设置方法 5.修改文件的拥有者 6.修改文件所属组 7.查看或修改文件权限掩码 …

轻松解决Android复杂数据结构序列化

问题描述 当我编写quickupload库时,因为需要在 Service中进行上传任务,向Service传递时我发现需要传递的数据很多并且结构复杂,如果处理不好就会导致以下几个问题 耗时: 需要更多时间进行开发和测试以确保正确的数据处理。容易出错: 由于手…

C语言:指针笔试题

// 输入某一年的第几天,计算并输出它是这一年的第几月第几日。 /* 函数功能: 对给定的某一年的第几天,计算它是这一年的第几月第几日。 函数入口参数: 整形变量year,存储年; 整形变量yearDay,存储某一年的第几天&am…