第3章:内容标识符(CID)
3.1 CID的结构和格式
CID(Content Identifier,内容标识符)是IPFS中用于唯一、无歧义地标识内容的核心机制。它是一种自描述(self-describing) 的标识符,内嵌了版本、数据编码格式及哈希算法等元信息,无需外部上下文即可解析其含义。其标准结构为:
<cid-version><multicodec><multihash>
CID v1 的组成字段说明:
- 版本号(CID version):标识CID的语法与语义规范(如
v0或v1),影响后续字段的解析方式; - 多编解码器(Multicodec):标识原始数据的序列化格式(如
dag-pb表示 IPLD DAG 的 Protocol Buffer 编码,raw表示未封装的原始字节流); - 多哈希(Multihash):包含哈希算法类型、摘要长度及实际哈希值三部分,确保哈希计算可验证、可移植。
💡 提示:CID 不是“地址”,也不隐含存储位置或网络路径——它仅承诺“内容即所指”。无论内容存于本地节点、远程网关,还是离线介质中,只要字节一致,CID 就完全相同。
3.2 CID版本(v0 vs v1)
CID v0(遗留格式):
QmYjtig7VJQ6XsnUjqqJvj7QaMcCAwtrgdfhz6EWTT22cP
```
- 以 `Qm` 开头(Base58BTC 编码的固定前缀);
- 隐式绑定 `dag-pb` 编解码器与 SHA-256 哈希算法;
- 本质是 CID v1 的特例(`v0` ≡ `v1 + codec=dag-pb + hash=sha2-256`),但缺乏显式声明能力。
**CID v1(当前推荐格式)**:
bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi ```
- 以
b开头(Base32 编码,兼容 URL 和 DNS 使用场景); - 显式携带版本、编解码器和多哈希字段,支持任意组合(如
cbor+blake2b-256); - 向前兼容 v0:所有 v0 CID 均可无损转换为 v1 形式(反之则需约定默认参数);
- 是 IPFS v0.5+ 及所有现代 IPLD 工具链的默认输出格式。
⚠️ 注意:v0 CID 已被标记为废弃(deprecated)。新项目应始终使用 v1,并在配置中显式指定
--cid-version=1(CLI)或version: 1(API 调用)。混合使用 v0/v1 可能导致跨工具链解析失败或语义误解。
3.3 多哈希(Multihash)算法
多哈希(Multihash)是一种轻量级、自描述的哈希值封装格式,旨在解决“哈希算法不可知”问题。其二进制结构严格定义为:
<hash-function-code><digest-length><digest-value>
其中:
hash-function-code:单字节(或双字节)算法标识符(如0x12表示 SHA-256);digest-length:单字节,表示后续摘要值的字节数(非位数);digest-value:定长原始哈希摘要(大端序,无填充)。
常见哈希算法及其 Multihash 代码:
| 算法 | Multihash 代码(十六进制) | 摘要长度 | 特点说明 |
|---|---|---|---|
| SHA-256 | 0x12 | 32 字节 | 广泛兼容,IPFS 默认选项 |
| SHA3-512 | 0x14 | 64 字节 | 抗量子增强,但计算开销较大 |
| Blake2b-256 | 0xb220 | 32 字节 | 性能优异,IPFS 推荐替代方案 |
💡 提示:Multihash 的设计使同一内容可同时拥有多个有效 CID(例如
bafy...sha2-256与bafy...blake2b-256),便于迁移算法或满足合规性要求,而无需修改内容本身。
3.4 CID的生成和使用
生成 CID 的典型方式(注意:输入必须是字节流,字符串需明确编码):
// ✅ 正确:显式指定 UTF-8 编码,避免平台默认差异
const { CID } = require('ipfs-http-client');
const uint8Array = new TextEncoder().encode('Hello IPFS');
async function generateCID() {
const cid = await CID.of(uint8Array);
console.log(cid.toString()); // 输出 v1 Base32 格式 CID
// 示例: bafkreif2p3qp4y2lv3txvij4nvqgg4ugypn5q5m5f5q5m5f5q5m5f5q5m
}
# ✅ 正确:使用 --cid-version=1 强制生成 v1,--only-hash 跳过上传
echo -n "Hello IPFS" | ipfs add --cid-version=1 --only-hash --quieter
# 输出: bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi
# ❌ 错误示例(不推荐):省略 --cid-version 将默认生成 v0
echo -n "Hello IPFS" | ipfs add --only-hash # 输出 Qm...(v0)
⚠️ 注意:
ipfs add默认对输入内容进行 DAG 封装(dag-pb),因此生成的 CID 对应的是封装后的节点,而非原始字节。若需原始内容 CID(如纯文本哈希),应使用--raw-leaves或直接调用CID.of()。
3.5 实际案例分析
CID 的核心价值在于内容可验证性(content verifiability):给定一个 CID,任何用户均可独立复现哈希计算,从而确认所获取数据的完整性与真实性,无需信任传输通道或服务提供方。
以下是一个端到端验证流程示例:
import ipfshttpclient
# 连接到本地 IPFS 节点(确保 API 服务已启用)
client = ipfshttpclient.connect('/ip4/127.0.0.1/tcp/5001/http')
# 步骤 1:添加文件并获取其 CID(v1 格式)
result = client.add('hello.txt', cid_version=1)
cid = result['Hash'] # 如: bafybeif2p3qp4y2lv3txvij4nvqgg4ugypn5q5m5f5q5m5f5q5m5f5q5m
print(f"文件 CID: {cid}")
# 步骤 2:通过 CID 获取内容(自动校验哈希)
try:
content = client.cat(cid)
print(f"文件内容: {content.decode('utf-8')}")
except ipfshttpclient.exceptions.TimeoutError:
print("❌ 超时:节点未找到该内容(可能尚未传播或未持久化)")
except ipfshttpclient.exceptions.ErrorResponse as e:
print(f"❌ 验证失败:{e}") # 例如哈希不匹配将触发此异常
💡 提示:
client.cat()在返回数据前会自动执行哈希校验——若下载内容与 CID 中声明的多哈希不一致,请求将直接失败并抛出异常。这是 IPFS 内置的安全保障,开发者无需手动实现校验逻辑。