使用HTTP协议连接
Created By RV, and licensed with Creative Commons "CC BY-NC-ND 4.0"
目的与场景
在这一章,讲解两个NodeJS节点如何通过HTTP协议互联,实现双向RPC调用。
一. 概念
1. HTTP协议
HTTP(HyperText Transfer Protocol)是最通用的网络协议,天然穿透防火墙和NAT,无需额外端口开放。
2. listen/attach
listen:创建HTTP服务器,监听端口,等待客户端连接attach:以HTTP客户端身份连接到服务器
在HTTP协议中:
- 提供服务的节点调用
listen('http://...'),创建HTTP服务器 - 调用服务的节点调用
attach('http://...'),连接服务器
3. 双向互调
HTTP连接建立后,两端节点均可注册服务,也可调用对方的服务,实现双向RPC。
二. 示例代码
在下边的示例中,我们将:
- nodeA作为HTTP服务器,监听端口8040,注册calc服务
- nodeB作为HTTP客户端,连接nodeA,注册str服务
- nodeB调用nodeA的calc服务
- nodeA调用nodeB的str服务(双向互调)
import Kree4n from '@kree4js/kree4n'
// Node A:HTTP服务器,注册calc服务
const nodeA = Kree4n.create('node-a', 'HTTP RPC server')
nodeA.register('calc', {
add (a, b) { return a + b },
multiply (a, b) { return a * b }
})
nodeA.listen('http://127.0.0.1:8040')
// Node B:HTTP客户端,注册str服务
const nodeB = Kree4n.create('node-b', 'HTTP RPC client')
nodeB.register('str', {
echo (msg) { return `Echo: ${msg}` },
greet (name) { return `Hello, ${name}! (via HTTP)` }
})
nodeB.attach('http://127.0.0.1:8040')
await nodeA.start()
await nodeB.start()
// node-b调用node-a的calc服务
const calc = nodeB.service('calc')
const addResult = await calc.add(10, 20)
// 30
const mulResult = await calc.multiply(6, 7)
// 42
// node-a调用node-b的str服务(双向)
const str = nodeA.service('str')
const echoResult = await str.echo('HTTP works!')
// "Echo: HTTP works!"
const greetResult = await str.greet('World')
// "Hello, World! (via HTTP)"
三. 须强调的细节
1. 在使用node:http和node:https
Kree4N内部使用了两个插件:@kree4js/http-listen和@kree4js/http-attach。
它们内部在使用NodeJS的http/https包。
NodeJS的http/https包,在建立连接后,是可以keep-alive,并且支持双向流式通信的。
”双向流式通信“,这一点有点意外,接受就好。
2. HTTP连接是持久连接
http-attach 内部使用HTTP持久连接(keep-alive),复用同一连接完成多次RPC调用,避免每次调用都建立新连接的开销。
3. NodJS HTTP不是mono-frame的
NodeJS HTTP协议下,使用流式通信,如果每次发送一个完整的帧,不能保证对端收到时完整的。
存在拖帧、粘帧问题,Kree4X在Transport层需要帧重组。
4. 双向互调能力
连接建立后,两端是对等的:
- 任意一端都可以注册服务
- 任意一端都可以调用对方注册的服务
- 不需要额外的反向连接
这一点,不同于传统的HTTP应用的单向Request-Response模型,了解就好。
四. 涉及到的API:
1. HTTP监听
/**
* 监听传入的连接。
* @param {string} url - 要监听的URL,例如 "http://127.0.0.1:8040"。
* @param {ConnectionOptions} [options] - 连接选项。
* @returns {this} 当前实例,用于链式调用。
*/
node.listen(url: string, options?: ConnectionOptions): this
2. HTTP连接
/**
* 通过HTTP协议连接到HTTP服务器。
* @param {string} url - 要连接的HTTP URL,例如 "http://127.0.0.1:8040"。
* @returns {this} 当前实例,用于链式调用。
*/
node.attach(url: string): this
五. 可运行代码
完整示例代码,参见:08-http-protocol.mjs