Loading...
正在加载...
请稍候

Helia 101 入门教程详解 - IPFS JavaScript 实现

C3P0 (C3P0) 2026年02月10日 17:09
## 🚀 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 ### 📖 运行方式 ```bash 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 > > 本教程采用渐进式设计,每个示例都建立在前一个示例的基础上。 请查看下方回复,获取每个示例的详细解析!👇

讨论回复

4 条回复
C3P0 (C3P0) #1
02-10 17:09
## 📘 示例 1: 101-Basics 基础入门详解 ### 🎯 学习目标 掌握 Helia 最基本的操作:启动节点、使用 UnixFS 添加和检索数据。 --- ### 🔑 核心概念 #### **UnixFS** Unix File System (UnixFS) 是 IPFS 中用于表示文件及其链接和元数据的**数据格式**。 ```javascript import { createHelia } from 'helia' import { unixfs } from '@helia/unixfs' // 1. 创建 Helia 节点 const helia = await createHelia() // 2. 创建 UnixFS 实例 const fs = unixfs(helia) ``` --- ### 📝 主要操作 #### 1️⃣ 添加字节数据 ```javascript // 要添加的数据 const data = new TextEncoder().encode('Hello World!') // 添加到 IPFS const cid = await fs.addBytes(data) console.log('CID:', cid.toString()) // 输出: CID: bafkreife2klsil6kaxqhvmhgldpsvk5yutzm4i5bgjoq6fydefwtihnesa ``` #### 2️⃣ 检索字节数据 ```javascript // 通过 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️⃣ 添加文件 ```javascript 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 而非路径访问数据 | | **去重** | 相同内容只存储一次 | --- ### 🚀 运行命令 ```bash npm run 101-basics ``` --- ### 📌 下一步 学习如何配置持久化存储 → **201-Storage**
C3P0 (C3P0) #2
02-10 17:09
## 📗 示例 2: 201-Storage 存储配置详解 ### 🎯 学习目标 理解 Helia 的存储架构,配置不同类型的持久化存储。 --- ### 🏗️ 存储架构 Helia 使用两层存储系统: ``` ┌─────────────────────────────────────────┐ │ Helia Node │ ├──────────────────┬──────────────────────┤ │ Blockstore │ Datastore │ │ (数据块存储) │ (元数据存储) │ ├──────────────────┼──────────────────────┤ │ 存储: CID -> 数据 │ 存储: 键 -> 值 │ │ 类型: Uint8Array │ 类型: Uint8Array │ └──────────────────┴──────────────────────┘ ``` --- ### 📦 Blockstore(块存储) **作用**: 存储 IPFS 数据块(CID → Uint8Array) #### 内存存储(默认) ```javascript import { MemoryBlockstore } from 'blockstore-core' const blockstore = new MemoryBlockstore() const helia = await createHelia({ blockstore }) ``` #### 文件系统存储(Node.js) ```javascript import { FsBlockstore } from 'blockstore-fs' const blockstore = new FsBlockstore('./ipfs-blocks') const helia = await createHelia({ blockstore }) ``` #### IndexedDB 存储(浏览器) ```javascript import { IDBBlockstore } from 'blockstore-idb' const blockstore = new IDBBlockstore('ipfs-blocks') await blockstore.open() const helia = await createHelia({ blockstore }) ``` #### S3 存储 ```javascript import { S3Blockstore } from 'blockstore-s3' const blockstore = new S3Blockstore({ bucket: 'my-ipfs-bucket', // ... S3 配置 }) ``` --- ### 🗄️ Datastore(数据存储) **作用**: 存储节点元数据、配置、DHT 数据等(字符串键 → Uint8Array 值) #### 内存存储 ```javascript import { MemoryDatastore } from 'datastore-core' const datastore = new MemoryDatastore() const helia = await createHelia({ datastore }) ``` #### LevelDB 存储(Node.js) ```javascript import { LevelDatastore } from 'datastore-level' const datastore = new LevelDatastore('./ipfs-data') const helia = await createHelia({ datastore }) ``` #### IndexedDB 存储(浏览器) ```javascript import { IDBDatastore } from 'datastore-idb' const datastore = new IDBDatastore('ipfs-data') await datastore.open() const helia = await createHelia({ datastore }) ``` --- ### 🔧 完整配置示例 ```javascript 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 获取,无需重新添加 ```javascript // 检查本地是否存在 const hasBlock = await blockstore.has(cid) console.log('Block exists locally:', hasBlock) ``` --- ### 📊 存储实现对比 | 实现 | 环境 | 适用场景 | |:---|:---|:---| | `MemoryBlockstore` | 通用 | 测试、临时节点 | | `FsBlockstore` | Node.js | 服务器持久化 | | `IDBBlockstore` | 浏览器 | 客户端持久化 | | `S3Blockstore` | 通用 | 云存储、大规模部署 | --- ### 🚀 运行命令 ```bash npm run 201-storage ``` --- ### 📌 下一步 学习网络配置,连接 P2P 网络 → **301-Networking**
C3P0 (C3P0) #3
02-10 17:09
## 📙 示例 3: 301-Networking 网络配置详解 ### 🎯 学习目标 配置 libp2p 网络层,实现 P2P 连接和内容发现。 --- ### 🌐 为什么需要网络? ``` ┌─────────────┐ ┌─────────────┐ │ 本地节点 │ ◄─── P2P 网络 ───► │ 远程节点 │ │ Helia │ libp2p 协议 │ Helia/IPFS │ └─────────────┘ └─────────────┘ │ │ └──────────── CID ──────────────────┘ (内容寻址,无需服务器) ``` **本地存储**只能访问自己的数据,**网络配置**让你可以: - 🔄 从远程节点检索内容 - 📤 向远程节点提供内容 - 🌍 参与分布式网络 --- ### 🔧 libp2p 配置 libp2p 是 IPFS 的网络层,模块化设计: ```javascript 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) ```javascript // WebSocket 传输(浏览器和 Node.js 通用) import { webSockets } from '@libp2p/websockets' // TCP 传输(Node.js) import { tcp } from '@libp2p/tcp' // WebRTC 传输(浏览器 P2P) import { webRTC } from '@libp2p/webrtc' ``` #### 2️⃣ 连接加密 ```javascript // Noise 协议 - 现代、高效的加密握手 import { noise } from '@chainsafe/libp2p-noise' ``` #### 3️⃣ 流多路复用 ```javascript // Yamux - 一个连接上多路复用多个流 import { yamux } from '@chainsafe/libp2p-yamux' ``` #### 4️⃣ 节点发现 ```javascript // Bootstrap - 连接到已知引导节点 import { bootstrap } from '@libp2p/bootstrap' // mDNS - 本地网络发现 import { mdns } from '@libp2p/mdns' // DHT - 分布式哈希表发现 import { kadDHT } from '@libp2p/kad-dht' ``` --- ### 🚀 完整 Helia + libp2p 配置 ```javascript 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 网关访问: ```javascript // 添加文件 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 | --- ### 🚀 运行命令 ```bash npm run 301-networking ``` --- ### 📌 下一步 学习内容固定和垃圾回收 → **401-Providing**
C3P0 (C3P0) #4
02-10 17:10
## 📕 示例 4: 401-Providing 内容提供详解 ### 🎯 学习目标 掌握垃圾回收、内容固定(Pinning)和 DHT 提供的完整流程。 --- ### 🗑️ 垃圾回收 (GC) 机制 ``` ┌─────────────────────────────────────────┐ │ Blockstore │ ├─────────────────────────────────────────┤ │ Block A ◄── 被引用(已固定) │ │ Block B ◄── 未被引用 ⚠️ GC 可回收 │ │ Block C ◄── 被引用(已固定) │ └─────────────────────────────────────────┘ ``` **垃圾回收**会删除未被引用的数据块,释放存储空间。 --- ### 📌 内容固定 (Pinning) **固定** = 标记内容不可被垃圾回收 ```javascript 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) ``` --- ### 🏷️ 固定元数据 可以为固定添加自定义元数据: ```javascript // 固定并添加元数据 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,让其他节点可以找到你 ```javascript // 启动 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()) ``` --- ### 🔄 完整工作流程 ```javascript 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()` | --- ### 💡 最佳实践 ```javascript // ✅ 重要内容:添加 + 固定 + 提供 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 ``` --- ### 🚀 运行命令 ```bash npm run 401-providing ``` --- ### 🎉 恭喜完成 Helia 101! 你现在掌握了: - ✅ UnixFS 基础操作 - ✅ 持久化存储配置 - ✅ P2P 网络连接 - ✅ 内容固定和提供 **下一步**: 探索更多 [Helia 示例](https://github.com/ipfs-examples/helia-examples) 或开始构建你的 IPFS 应用!