2026 年 IPFS CID 完整指南:内容寻址原理(含代码示例)

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

Nacho Coll作者: 更新时间: 15 分钟阅读
IPFS CID实战指南:CIDv0与CIDv1对比、内容寻址原理、用Node.js和Python生成CID、完整性验证方法,以及2026年最新最佳实践全面解析。

如果你接触过 IPFS (InterPlanetary File System),很可能见过形如 QmYwAPJzv5CZsnA625s3Xf2nemtYgPpHdWEz79ojWnPbdGbafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi 的字符串。它们并非随机乱码 —— 它们是 Content Identifier (CID),IPFS 内容寻址系统的核心支柱。

理解 CID 对任何在 IPFS 上构建的人来说都至关重要,无论你是上传文件、构建去中心化应用,还是实现内容分发系统。本指南将拆解你需要了解的关于 IPFS CID 的所有内容、内容寻址如何工作,以及如何在你的项目中开始使用它们。

IPFS Ninja

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 时,你信任的是:

  1. 域名所有者没有更改内容
  2. 服务器在线且可访问
  3. 内容没有被篡改

使用 CID 的内容寻址:

  1. 不可变性:CID 保证内容没有改变
  2. 去中心化:可以从任何拥有该内容的 IPFS 节点检索
  3. 验证:你可以加密验证收到的是正确的内容
  4. 效率:相同内容自动去重

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. 哈希过程#

每段内容经历:

  1. 序列化:内容按其编解码器格式化
  2. 哈希:加密哈希函数处理序列化数据
  3. Multihash 创建:哈希被包装上算法和长度信息
  4. 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 带宽。无需信用卡。

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.

返回博客

相关文章