Helia 101 入门教程详解 - IPFS JavaScript 实现
🚀 Helia 101 入门教程简介
Helia 是 IPFS 协议的现代化 TypeScript 实现,专为 JavaScript 和浏览器环境设计。
📚 教程结构
Helia 101 是一个渐进式学习教程,分为 4 个核心示例:
| 示例 | 主题 | 核心内容 |
|---|---|---|
| 101-Basics | 基础入门 | UnixFS 交互、添加/检索字节、目录和文件 |
| 201-Storage | 存储配置 | Blockstore 和 Datastore 配置、持久化存储 |
| 301-Networking | 网络配置 | libp2p 网络层、P2P 连接、内容发现 |
| 401-Providing | 内容提供 | 垃圾回收、Pinning 固定、DHT 提供 |
🎯 学习目标
完成本教程后,你将能够:
- ✅ 启动 Helia 节点
- ✅ 使用 UnixFS 添加和检索文件
- ✅ 配置持久化存储(内存/文件系统/IndexedDB/S3)
- ✅ 配置 libp2p 网络进行 P2P 通信
- ✅ 固定内容并防止垃圾回收
- ✅ 通过 IPFS 网关访问内容
🔧 环境要求
- Node.js 和 npm
- Git
📖 运行方式
npm install
npm run 101-basics # 基础示例
npm run 201-storage # 存储示例
npm run 301-networking # 网络示例
npm run 401-providing # 提供示例
---
> 💡 GitHub 仓库: https://github.com/ipfs-examples/helia-101 > > 本教程采用渐进式设计,每个示例都建立在前一个示例的基础上。
请查看下方回复,获取每个示例的详细解析!👇
📘 示例 1: 101-Basics 基础入门详解
🎯 学习目标
掌握 Helia 最基本的操作:启动节点、使用 UnixFS 添加和检索数据。---
🔑 核心概念
#### UnixFS Unix File System (UnixFS) 是 IPFS 中用于表示文件及其链接和元数据的数据格式。
import { createHelia } from 'helia'
import { unixfs } from '@helia/unixfs'
// 1. 创建 Helia 节点
const helia = await createHelia()
// 2. 创建 UnixFS 实例
const fs = unixfs(helia)
---
📝 主要操作
#### 1️⃣ 添加字节数据
// 要添加的数据
const data = new TextEncoder().encode('Hello World!')
// 添加到 IPFS
const cid = await fs.addBytes(data)
console.log('CID:', cid.toString())
// 输出: CID: bafkreife2klsil6kaxqhvmhgldpsvk5yutzm4i5bgjoq6fydefwtihnesa
#### 2️⃣ 检索字节数据
// 通过 CID 读取数据
const chunks = []
for await (const chunk of fs.cat(cid)) {
chunks.push(chunk)
}
// 合并并解码
const retrieved = new TextDecoder().decode(Buffer.concat(chunks))
console.log('Retrieved:', retrieved)
// 输出: Hello World!
#### 3️⃣ 添加文件
import { globSource } from 'ipfs-utils/files/glob-source'
// 添加单个文件
const cid = await fs.addFile({
path: 'hello.txt',
content: new TextEncoder().encode('Hello World!')
})
// 添加目录
const dirCid = await fs.addDirectory()
---
🧩 CID 说明
CID (Content Identifier) 是内容的唯一标识符:
- 基于内容哈希生成
- 相同内容 = 相同 CID
- 不可篡改(内容改变 → CID 改变)
示例 CID: bafkreife2klsil6kaxqhvmhgldpsvk5yutzm4i5bgjoq6fydefwtihnesa
└─ bafkrei = CIDv1 + raw codec + sha2-256
---
💡 关键要点
| 要点 | 说明 |
|---|---|
| 默认存储 | 内存存储(重启后数据丢失) |
| 数据分块 | 大文件自动分块存储 |
| 内容寻址 | 通过 CID 而非路径访问数据 |
| 去重 | 相同内容只存储一次 |
🚀 运行命令
npm run 101-basics
---
📌 下一步
学习如何配置持久化存储 → 201-Storage📗 示例 2: 201-Storage 存储配置详解
🎯 学习目标
理解 Helia 的存储架构,配置不同类型的持久化存储。---
🏗️ 存储架构
Helia 使用两层存储系统:
┌─────────────────────────────────────────┐
│ Helia Node │
├──────────────────┬──────────────────────┤
│ Blockstore │ Datastore │
│ (数据块存储) │ (元数据存储) │
├──────────────────┼──────────────────────┤
│ 存储: CID -> 数据 │ 存储: 键 -> 值 │
│ 类型: Uint8Array │ 类型: Uint8Array │
└──────────────────┴──────────────────────┘
---
📦 Blockstore(块存储)
作用: 存储 IPFS 数据块(CID → Uint8Array)
#### 内存存储(默认)
import { MemoryBlockstore } from 'blockstore-core'
const blockstore = new MemoryBlockstore()
const helia = await createHelia({ blockstore })
#### 文件系统存储(Node.js)
import { FsBlockstore } from 'blockstore-fs'
const blockstore = new FsBlockstore('./ipfs-blocks')
const helia = await createHelia({ blockstore })
#### IndexedDB 存储(浏览器)
import { IDBBlockstore } from 'blockstore-idb'
const blockstore = new IDBBlockstore('ipfs-blocks')
await blockstore.open()
const helia = await createHelia({ blockstore })
#### S3 存储
import { S3Blockstore } from 'blockstore-s3'
const blockstore = new S3Blockstore({
bucket: 'my-ipfs-bucket',
// ... S3 配置
})
---
🗄️ Datastore(数据存储)
作用: 存储节点元数据、配置、DHT 数据等(字符串键 → Uint8Array 值)
#### 内存存储
import { MemoryDatastore } from 'datastore-core'
const datastore = new MemoryDatastore()
const helia = await createHelia({ datastore })
#### LevelDB 存储(Node.js)
import { LevelDatastore } from 'datastore-level'
const datastore = new LevelDatastore('./ipfs-data')
const helia = await createHelia({ datastore })
#### IndexedDB 存储(浏览器)
import { IDBDatastore } from 'datastore-idb'
const datastore = new IDBDatastore('ipfs-data')
await datastore.open()
const helia = await createHelia({ datastore })
---
🔧 完整配置示例
import { createHelia } from 'helia'
import { FsBlockstore } from 'blockstore-fs'
import { LevelDatastore } from 'datastore-level'
// 持久化存储配置
const blockstore = new FsBlockstore('./ipfs-blocks')
const datastore = new LevelDatastore('./ipfs-data')
const helia = await createHelia({
blockstore,
datastore
})
console.log('Helia node with persistent storage started!')
console.log('Peer ID:', helia.libp2p.peerId.toString())
---
🧪 验证持久化
运行两次示例,你会发现: 1. 第一次: 添加文件,生成 CID 2. 第二次: 相同 CID 直接从本地 blockstore 获取,无需重新添加
// 检查本地是否存在
const hasBlock = await blockstore.has(cid)
console.log('Block exists locally:', hasBlock)
---
📊 存储实现对比
| 实现 | 环境 | 适用场景 |
|---|---|---|
MemoryBlockstore | 通用 | 测试、临时节点 |
FsBlockstore | Node.js | 服务器持久化 |
IDBBlockstore | 浏览器 | 客户端持久化 |
S3Blockstore | 通用 | 云存储、大规模部署 |
🚀 运行命令
npm run 201-storage
---
📌 下一步
学习网络配置,连接 P2P 网络 → 301-Networking📙 示例 3: 301-Networking 网络配置详解
🎯 学习目标
配置 libp2p 网络层,实现 P2P 连接和内容发现。---
🌐 为什么需要网络?
┌─────────────┐ ┌─────────────┐
│ 本地节点 │ ◄─── P2P 网络 ───► │ 远程节点 │
│ Helia │ libp2p 协议 │ Helia/IPFS │
└─────────────┘ └─────────────┘
│ │
└──────────── CID ──────────────────┘
(内容寻址,无需服务器)
本地存储只能访问自己的数据,网络配置让你可以:
- 🔄 从远程节点检索内容
- 📤 向远程节点提供内容
- 🌍 参与分布式网络
🔧 libp2p 配置
libp2p 是 IPFS 的网络层,模块化设计:
import { createLibp2p } from 'libp2p'
import { identifyService } from 'libp2p/identify'
import { noise } from '@chainsafe/libp2p-noise'
import { yamux } from '@chainsafe/libp2p-yamux'
import { webSockets } from '@libp2p/websockets'
import { bootstrap } from '@libp2p/bootstrap'
const libp2p = await createLibp2p({
// 1. 传输层
transports: [webSockets()],
// 2. 连接加密
connectionEncrypters: [noise()],
// 3. 流多路复用
streamMuxers: [yamux()],
// 4. 节点发现
peerDiscovery: [
bootstrap({
list: [
"/dnsaddr/bootstrap.libp2p.io/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN",
"/dnsaddr/bootstrap.libp2p.io/p2p/QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa"
]
})
],
// 5. 服务
services: {
identify: identifyService()
}
})
---
🧩 核心组件解析
#### 1️⃣ 传输层 (Transports)
// WebSocket 传输(浏览器和 Node.js 通用)
import { webSockets } from '@libp2p/websockets'
// TCP 传输(Node.js)
import { tcp } from '@libp2p/tcp'
// WebRTC 传输(浏览器 P2P)
import { webRTC } from '@libp2p/webrtc'
#### 2️⃣ 连接加密
// Noise 协议 - 现代、高效的加密握手
import { noise } from '@chainsafe/libp2p-noise'
#### 3️⃣ 流多路复用
// Yamux - 一个连接上多路复用多个流
import { yamux } from '@chainsafe/libp2p-yamux'
#### 4️⃣ 节点发现
// Bootstrap - 连接到已知引导节点
import { bootstrap } from '@libp2p/bootstrap'
// mDNS - 本地网络发现
import { mdns } from '@libp2p/mdns'
// DHT - 分布式哈希表发现
import { kadDHT } from '@libp2p/kad-dht'
---
🚀 完整 Helia + libp2p 配置
import { createHelia } from 'helia'
import { createLibp2p } from 'libp2p'
import { noise } from '@chainsafe/libp2p-noise'
import { yamux } from '@chainsafe/libp2p-yamux'
import { webSockets } from '@libp2p/websockets'
import { bootstrap } from '@libp2p/bootstrap'
// 创建 libp2p 节点
const libp2p = await createLibp2p({
transports: [webSockets()],
connectionEncrypters: [noise()],
streamMuxers: [yamux()],
peerDiscovery: [
bootstrap({
list: [
"/dnsaddr/bootstrap.libp2p.io/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN",
"/dnsaddr/bootstrap.libp2p.io/p2p/QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa",
"/dnsaddr/bootstrap.libp2p.io/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb",
"/dnsaddr/bootstrap.libp2p.io/p2p/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt"
]
})
]
})
// 创建 Helia 节点(使用自定义 libp2p)
const helia = await createHelia({ libp2p })
console.log('Node started!')
console.log('Peer ID:', libp2p.peerId.toString())
---
🌍 通过网关访问内容
添加文件后,你可以在任何 IPFS 网关访问:
// 添加文件
const cid = await fs.addBytes(data)
console.log('Added file:', cid.toString())
// Added file: bafkreife2klsil6kaxqhvmhgldpsvk5yutzm4i5bgjoq6fydefwtihnesa
访问链接:
https://ipfs.io/ipfs/bafkreife2klsil6kaxqhvmhgldpsvk5yutzm4i5bgjoq6fydefwtihnesa
---
📊 网络配置对比
| 环境 | 推荐传输 | 发现方式 |
|---|---|---|
| 浏览器 | WebSocket + WebRTC | Bootstrap, DHT |
| Node.js | TCP + WebSocket | Bootstrap, mDNS, DHT |
| 混合 | WebSocket | Bootstrap |
🚀 运行命令
npm run 301-networking
---
📌 下一步
学习内容固定和垃圾回收 → 401-Providing📕 示例 4: 401-Providing 内容提供详解
🎯 学习目标
掌握垃圾回收、内容固定(Pinning)和 DHT 提供的完整流程。---
🗑️ 垃圾回收 (GC) 机制
┌─────────────────────────────────────────┐
│ Blockstore │
├─────────────────────────────────────────┤
│ Block A ◄── 被引用(已固定) │
│ Block B ◄── 未被引用 ⚠️ GC 可回收 │
│ Block C ◄── 被引用(已固定) │
└─────────────────────────────────────────┘
垃圾回收会删除未被引用的数据块,释放存储空间。
---
📌 内容固定 (Pinning)
固定 = 标记内容不可被垃圾回收
import { createHelia } from 'helia'
const helia = await createHelia()
// 添加文件
const cid = await fs.addBytes(data)
// 1️⃣ 固定 CID(防止被 GC)
await helia.pins.add(cid)
console.log('Pinned:', cid.toString())
// 2️⃣ 查看固定列表
for await (const pin of helia.pins.ls()) {
console.log('Pinned CID:', pin.cid.toString())
}
// 3️⃣ 取消固定
await helia.pins.rm(cid)
---
🏷️ 固定元数据
可以为固定添加自定义元数据:
// 固定并添加元数据
await helia.pins.add(cid, {
metadata: {
name: 'important-document.pdf',
timestamp: Date.now(),
tags: ['work', 'urgent']
}
})
// 查看带元数据的固定
for await (const pin of helia.pins.ls()) {
console.log('CID:', pin.cid.toString())
console.log('Metadata:', pin.metadata)
}
---
🌍 DHT 提供 (Providing)
提供 = 向 DHT 宣告你拥有某个 CID,让其他节点可以找到你
// 启动 DHT 服务
import { kadDHT } from '@libp2p/kad-dht'
const libp2p = await createLibp2p({
// ... 其他配置
services: {
dht: kadDHT()
}
})
const helia = await createHelia({ libp2p })
// 提供 CID 到 DHT
await helia.routing.provide(cid)
console.log('Provided CID to DHT:', cid.toString())
---
🔄 完整工作流程
import { createHelia } from 'helia'
import { unixfs } from '@helia/unixfs'
// 1. 启动节点
const helia = await createHelia()
const fs = unixfs(helia)
// 2. 添加内容
const data = new TextEncoder().encode('Hello IPFS World!')
const cid = await fs.addBytes(data)
console.log('✅ Added:', cid.toString())
// 3. 固定内容(防止 GC)
await helia.pins.add(cid)
console.log('📌 Pinned')
// 4. 提供到 DHT(让网络发现)
await helia.routing.provide(cid)
console.log('🌍 Provided to DHT')
// 5. 运行垃圾回收(未固定内容将被删除)
await helia.gc()
console.log('🗑️ GC completed')
// 6. 验证内容仍在
const chunks = []
for await (const chunk of fs.cat(cid)) {
chunks.push(chunk)
}
const retrieved = new TextDecoder().decode(Buffer.concat(chunks))
console.log('✅ Retrieved:', retrieved)
---
📊 关键概念对比
| 概念 | 作用 | 命令 |
|---|---|---|
| 添加 (Add) | 将数据存入 blockstore | fs.addBytes() |
| 固定 (Pin) | 防止内容被 GC 删除 | helia.pins.add() |
| 提供 (Provide) | 向 DHT 宣告拥有内容 | helia.routing.provide() |
| GC | 清理未固定内容 | helia.gc() |
💡 最佳实践
// ✅ 重要内容:添加 + 固定 + 提供
await fs.addBytes(data)
await helia.pins.add(cid)
await helia.routing.provide(cid)
// ✅ 临时内容:仅添加(依赖 GC 自动清理)
await fs.addBytes(tempData)
// 不固定,下次 GC 自动删除
// ✅ 定期维护
setInterval(async () => {
await helia.gc()
}, 60 * 60 * 1000) // 每小时运行一次 GC
---
🚀 运行命令
npm run 401-providing
---
🎉 恭喜完成 Helia 101!
你现在掌握了:
- ✅ UnixFS 基础操作
- ✅ 持久化存储配置
- ✅ P2P 网络连接
- ✅ 内容固定和提供
🌟 智谱 GLM-5 已上线
我正在智谱大模型开放平台 BigModel.cn 上打造 AI 应用,智谱新一代旗舰模型 GLM-5 已上线,在推理、代码、智能体综合能力达到开源模型 SOTA 水平。
🎁 领取 2000万 Tokens