2026 年 IPFS CID 完整指南:内容寻址原理(含代码示例)
IPFS CID实战指南:CIDv0与CIDv1对比、内容寻址原理、用Node.js和Python生成CID、完整性验证方法,以及2026年最新最佳实践全面解析。

如果你接触过 IPFS (InterPlanetary File System),很可能见过形如 QmYwAPJzv5CZsnA625s3Xf2nemtYgPpHdWEz79ojWnPbdG 或 bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi 的字符串。它们并非随机乱码 —— 它们是 Content Identifier (CID),IPFS 内容寻址系统的核心支柱。
理解 CID 对任何在 IPFS 上构建的人来说都至关重要,无论你是上传文件、构建去中心化应用,还是实现内容分发系统。本指南将拆解你需要了解的关于 IPFS CID 的所有内容、内容寻址如何工作,以及如何在你的项目中开始使用它们。

5行代码生成CID(Python)#
import hashlib, base58
def cidv0(content: bytes) -> str:
sha256 = hashlib.sha256(content).digest()
return base58.b58encode(b"\x12\x20" + sha256).decode()
print(cidv0(b"hello world"))
# QmaozNR7DZHQK1ZcU9p7QdrshMvXqWK6gpvBw3cWE69N3T这个 CID 任何人都能复现——在地球上任何地方用相同的字节重新运行同样的代码,都会得到相同的字符串。这正是内容寻址的本质。
Node.js 等效实现:
import { sha256 } from 'multiformats/hashes/sha2';
import { CID } from 'multiformats/cid';
const bytes = new TextEncoder().encode('hello world');
const hash = await sha256.digest(bytes);
const cid = CID.create(1, 0x55, hash); // version 1, raw codec
console.log(cid.toString());
// bafkreif7l7mvyofhyo6fgs6mjf5gguvm5jcahzgvfb3o7t5lmhz3...什么是 IPFS CID?#
Content Identifier (CID) 是表示 IPFS 中一段内容的唯一指纹。与指向位置的传统 Web URL (例如 https://example.com/file.pdf) 不同,CID 指向内容本身,无论它存储在哪里。
可以这样理解:
- 基于位置的寻址:“去主街 123 号,要那本红书”
- 基于内容的寻址:“找 ISBN 978-0-123456-78-9 的书”(它在哪家图书馆都无所谓)
CID 的工作方式类似 —— 它们通过加密哈希识别内容,使内容具有不可变性和可验证性。如果文件中哪怕只改动一个字节,CID 也会完全改变。
为什么内容寻址很重要#
传统的 Web 架构依赖基于位置的寻址。当你访问 https://example.com/image.jpg 时,你信任的是:
- 域名所有者没有更改内容
- 服务器在线且可访问
- 内容没有被篡改
使用 CID 的内容寻址:
- 不可变性:CID 保证内容没有改变
- 去中心化:可以从任何拥有该内容的 IPFS 节点检索
- 验证:你可以加密验证收到的是正确的内容
- 效率:相同内容自动去重
CID 的剖析#
让我们剖析一个典型的 CID,理解它的组成部分:
bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi
└─┬─┘└─────────────────┬─────────────────────────────────┘
│ │
│ └─ 内容哈希 (Base32 编码)
└─ Multibase 前缀 (指示编码方式)一个 CID 包含若干信息片段:
1. Multibase 前缀#
首字符指示 CID 是如何编码的:
Q= Base58 编码 (CIDv0)b= Base32 编码 (CIDv1)f= Base16/十六进制 (CIDv1)z= Base58 (CIDv1)
2. CID 版本#
- CIDv0:总是以
Qm开头,使用 SHA-256,限定为 DAG-PB 编解码器 - CIDv1:更灵活,支持多种哈希函数和编解码器
3. Multicodec#
指定内容如何结构化 (DAG-PB、DAG-CBOR、原始字节等)
4. Multihash#
内容的实际加密哈希,包括:
- 哈希函数标识符 (通常为 SHA-256)
- 哈希长度
- 哈希摘要
CIDv0 vs CIDv1:理解差异#
IPFS 经历了两个主要 CID 版本的演进,每个版本具有不同的特性:
CIDv0:原始格式#
CIDv0 的 CID 总是以 Qm 开头,形如:
QmYwAPJzv5CZsnA625s3Xf2nemtYgPpHdWEz79ojWnPbdG特性:
- 仅 Base58 编码
- 仅 SHA-256 哈希函数
- 仅 DAG-PB (Protobuf) 编解码器
- 46 个字符长
- 与所有 IPFS 实现向后兼容
何时使用 CIDv0:
- 与旧 IPFS 节点的最大兼容性
- 与期望
Qm前缀的现有系统协作 - 文件存储 (最常见用例)
CIDv1:现代标准#
CIDv1 的 CID 更灵活,可能形如:
bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi # Base32
zb2rhj7crUKTQYRGCRATFaQ6YFLTde2YzdqbbhAASkL9uRDXn # Base58
f01551220d1e2c35... # Base16特性:
- 多种编码格式 (Base32、Base58、Base16)
- 支持不同哈希函数 (SHA-256、SHA-512、BLAKE2 等)
- 多种编解码器 (Raw、DAG-CBOR、DAG-JSON 等)
- 自描述格式
- 使用 Base32 时大小写不敏感
何时使用 CIDv1:
- 构建新应用
- 需要大小写不敏感的标识符
- 处理结构化数据 (JSON、CBOR)
- 使用替代哈希函数
版本间转换#
你可以在版本间转换 CID,同时保持相同的内容引用:
// CIDv0
const cidv0 = "QmYwAPJzv5CZsnA625s3Xf2nemtYgPpHdWEz79ojWnPbdG";
// Convert to CIDv1 Base32
const cidv1 = "bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi";
// Both reference the same content!内容寻址如何工作#
IPFS 中的内容寻址遵循一个确定性流程,确保相同内容总是产生相同 CID:
1. 内容准备#
当你向 IPFS 添加内容时,它会先被分解:
- 小文件:作为单一区块存储
- 大文件:分割成块并组织在 Merkle DAG (有向无环图) 中
- 目录:表示为链接到文件的 DAG 结构
2. 哈希过程#
每段内容经历:
- 序列化:内容按其编解码器格式化
- 哈希:加密哈希函数处理序列化数据
- Multihash 创建:哈希被包装上算法和长度信息
- CID 组装:版本、编解码器和 multihash 组合
3. Merkle DAG 结构#
IPFS 在 Merkle DAG 中组织内容,其中:
- 每个节点有一个 CID
- 父节点通过 CID 引用子节点
- 对任何节点的更改会沿树向上传播
- 整个结构可以加密验证
Root CID: bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi
├── file1.txt (QmHash1...)
├── file2.jpg (QmHash2...)
└── subdirectory/
├── file3.pdf (QmHash3...)
└── file4.mp4 (QmHash4...)实践示例:使用 CID#
让我们使用 IPFS Ninja 的 API 探索如何在实践中使用 CID:
上传内容并获取 CID#
// Upload a file and get its CID
const uploadFile = async (content, filename) => {
const response = await fetch('https://api.ipfs.ninja/upload/new', {
method: 'POST',
headers: {
'X-Api-Key': 'bws_1234567890abcdef1234567890abcdef12345678',
'Content-Type': 'application/json'
},
body: JSON.stringify({
content: btoa(content), // Base64 encode binary content
description: `Upload of ${filename}`
})
});
const result = await response.json();
console.log('CID:', result.cid);
console.log('IPFS URL:', result.uris.ipfs);
console.log('HTTP URL:', result.uris.url);
return result.cid;
};
// Example usage
uploadFile('Hello, IPFS!', 'greeting.txt');
// Returns: bafkreifjxz6zwqh27k5xnr5qfbx4w6n5vuwwwdcngguwjewzj2e3xxfgvi通过 CID 固定已有内容#
如果已经有 CID,你可以固定它以确保内容保持可用:
const pinByCID = async (cid) => {
const response = await fetch('https://api.ipfs.ninja/pin', {
method: 'POST',
headers: {
'X-Api-Key': 'bws_1234567890abcdef1234567890abcdef12345678',
'Content-Type': 'application/json'
},
body: JSON.stringify({
cid: cid,
description: 'Pinned via API'
})
});
const result = await response.json();
console.log('Pinned CID:', result.cid);
return result;
};
// Pin the "Hello World" of IPFS
pinByCID('QmWATWQ7fVPP2EFGu71UkfnqhYXDYH566qy47CnJDgvs8u');通过 CID 访问内容#
一旦有了 CID,你可以通过多种方式访问内容:
// Direct IPFS gateway access
const ipfsUrl = `https://ipfs.ninja/ipfs/${cid}`;
// Custom gateway (if configured)
const customGatewayUrl = `https://my-app.gw.ipfs.ninja/ipfs/${cid}`;
// Fetch content programmatically
const fetchContent = async (cid) => {
const response = await fetch(`https://ipfs.ninja/ipfs/${cid}`);
const content = await response.text();
return content;
};开发者的 CID 最佳实践#
1. 始终验证 CID#
在应用中使用 CID 之前,验证其格式:
const isValidCID = (cid) => {
// Basic validation patterns
const cidv0Pattern = /^Qm[1-9A-HJ-NP-Za-km-z]{44}$/;
const cidv1Pattern = /^[bf][a-z2-7]{58}$/;
return cidv0Pattern.test(cid) || cidv1Pattern.test(cid);
};2. 处理两种 CID 版本#
你的应用应该同时支持 CIDv0 和 CIDv1:
const normalizeCID = (cid) => {
if (cid.startsWith('Qm')) {
// CIDv0 - can convert to CIDv1 if needed
return cid;
} else if (cid.startsWith('b') || cid.startsWith('f') || cid.startsWith('z')) {
// CIDv1
return cid;
} else {
throw new Error('Invalid CID format');
}
};3. 缓存 CID 映射#
如果你频繁生成 CID,考虑缓存:
const cidCache = new Map();
const getCachedCID = (content) => {
const contentHash = btoa(content);
if (cidCache.has(contentHash)) {
return cidCache.get(contentHash);
}
// Upload and cache result
return uploadFile(content).then(cid => {
cidCache.set(contentHash, cid);
return cid;
});
};4. 使用有意义的描述#
上传内容时,包含描述性元数据:
const uploadWithMetadata = async (content, metadata) => {
return fetch('https://api.ipfs.ninja/upload/new', {
method: 'POST',
headers: {
'X-Api-Key': 'bws_1234567890abcdef1234567890abcdef12345678',
'Content-Type': 'application/json'
},
body: JSON.stringify({
content: btoa(content),
description: metadata.name || 'Uploaded file',
metadata: {
filename: metadata.filename,
contentType: metadata.contentType,
uploadedAt: new Date().toISOString(),
version: metadata.version || '1.0'
}
})
});
};CID 的常见用例#
1. 静态网站部署#
将整个网站部署到 IPFS 并通过 CID 引用:
// Upload website directory structure
const deployWebsite = async (files) => {
const uploads = await Promise.all(
files.map(file => uploadFile(file.content, file.path))
);
// Root CID references entire site
const rootCID = uploads.find(u => u.path === 'index.html').cid;
console.log(`Website deployed: https://ipfs.ninja/ipfs/${rootCID}`);
return rootCID;
};要了解更多关于部署网站的内容,请查看我们关于如何上传文件到 IPFS 的指南。
2. NFT 元数据存储#
使用 CID 不可变地存储 NFT 元数据:
const nftMetadata = {
name: "My Awesome NFT",
description: "A unique digital collectible",
image: "ipfs://bafkreibc5sgo2plmjkq2tzmhrn54bk3crhnqekiy7u66fqvqm37pu2e5gw",
attributes: [
{ trait_type: "Color", value: "Blue" },
{ trait_type: "Rarity", value: "Epic" }
]
};
const metadataCID = await uploadFile(
JSON.stringify(nftMetadata, null, 2),
'metadata.json'
);
// Use in smart contract
console.log(`Token URI: ipfs://${metadataCID}`);3. 内容分发#
使用 CID 进行分布式内容分发:
// Upload once, access everywhere
const distributeContent = async (content) => {
const cid = await uploadFile(content, 'content.txt');
// Content available via multiple gateways
const gateways = [
`https://ipfs.ninja/ipfs/${cid}`,
`https://ipfs.io/ipfs/${cid}`,
`https://cloudflare-ipfs.com/ipfs/${cid}`
];
return { cid, gateways };
};理解 IPFS pinning 与 CID#
CID 默认是临时的 —— 需要被”固定”才能保持可用。在我们关于 IPFS pinning 是什么 的综合指南中了解更多。
选择 IPFS pinning 服务时,考虑阅读我们的 IPFS Ninja vs Pinata 比较或浏览我们今天可用的最佳 IPFS pinning 服务 综述。
30 秒创建你的第一个 CID#
准备好生成你的第一个 CID 了吗?这是使用 IPFS Ninja API 的快速示例:
# Using curl (replace with your actual API key)
curl -X POST https://api.ipfs.ninja/upload/new \
-H "X-Api-Key: bws_YOUR_API_KEY_HERE" \
-H "Content-Type: application/json" \
-d '{
"content": "SGVsbG8sIElQRlMgV29ybGQh",
"description": "My first IPFS upload"
}'// Using JavaScript
const createFirstCID = async () => {
const response = await fetch('https://api.ipfs.ninja/upload/new', {
method: 'POST',
headers: {
'X-Api-Key': 'bws_YOUR_API_KEY_HERE',
'Content-Type': 'application/json'
},
body: JSON.stringify({
content: btoa('Hello, IPFS World!'), // Base64: "SGVsbG8sIElQRlMgV29ybGQh"
description: 'My first IPFS upload'
})
});
const result = await response.json();
console.log('🎉 Your first CID:', result.cid);
console.log('🌐 Access it at:', result.uris.url);
return result;
};
createFirstCID();这将返回类似:
{
"cid": "bafkreif2pall7dybz7vecqka3zo24irdwabf7rbiiweuhau7a2hjlqvfjw",
"sizeMB": 0.000017,
"uris": {
"ipfs": "ipfs://bafkreif2pall7dybz7vecqka3zo24irdwabf7rbiiweuhau7a2hjlqvfjw",
"url": "https://ipfs.ninja/ipfs/bafkreif2pall7dybz7vecqka3zo24irdwabf7rbiiweuhau7a2hjlqvfjw"
}
}更多详细的 API 示例,请查看我们的 IPFS 上传 API 教程。
结论#
CID 是 IPFS 内容寻址系统的基础,提供不可变、可验证和去中心化的内容识别。理解它们如何工作 —— 从 CIDv0 vs CIDv1 的技术细节到实际实现模式 —— 对构建健壮的去中心化应用至关重要。
关键要点:
- CID 唯一标识内容,而不是位置
- CIDv0 提供最大兼容性,CIDv1 提供灵活性
- 内容寻址支持验证和去重
- 正确的 CID 处理对生产应用至关重要
无论你是存储 NFT 元数据、部署去中心化网站,还是构建内容分发系统,CID 都为真正去中心化的应用提供了你所需要的可靠基础。
准备好开始 pinning 了吗? 创建免费账户 —— 50 文件、1 GB 存储、每月 2 GB 带宽。无需信用卡。
关于本文
本文由 AI 辅助撰写,经人工审核,并在发布前对照 IPFS.NINJA 实际平台进行了核实。 了解我们如何在内容中使用 AI .

关于作者
Nacho Coll
Founder & Engineer at IPFS.NINJA
Nacho founded IPFS.NINJA to make content-addressed storage feel as simple as an S3 PUT — a single API call, a permanent CID, no wallets or peer discovery to reason about. Writes about IPFS internals, decentralized storage patterns, and the pinning-service landscape from the operator side of the wire.
