· Nacho Coll · Guides  · 12 分鐘閱讀

IPFS CID 完整解析:它是什麼以及內容定址如何運作

清晰技術性地說明 IPFS 內容識別碼 (CIDs)。內容定址如何運作、CID 版本以及如何建立你的第一個 CID。

清晰技術性地說明 IPFS 內容識別碼 (CIDs)。內容定址如何運作、CID 版本以及如何建立你的第一個 CID。

如果你曾使用過 IPFS(InterPlanetary File System,星際檔案系統),你可能遇過像 QmYwAPJzv5CZsnA625s3Xf2nemtYgPpHdWEz79ojWnPbdGbafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi 的字串。這些不是隨機的亂碼——它們是內容識別碼(CIDs),IPFS 內容定址系統的骨幹。

理解 CIDs 對任何在 IPFS 上構建應用的人來說都至關重要,無論你是上傳檔案、構建去中心化應用,還是實作內容分發系統。本指南將分解你需要知道關於 IPFS CIDs 的一切、內容定址如何運作,以及如何在你的專案中開始使用它們。

IPFS Ninja

什麼是 IPFS CID?

**內容識別碼(CID)**是代表 IPFS 上一段內容的唯一指紋。與指向某個位置的傳統 web URL(如 https://example.com/file.pdf)不同,CIDs 指向內容本身,不管它儲存在哪裡。

這樣想:

  • 基於位置的定址:「去主街 123 號要那本紅色的書」
  • 基於內容的定址:「找到 ISBN 為 978-0-123456-78-9 的書」(不管哪間圖書館有它)

CIDs 以類似方式運作——它們根據內容的密碼學雜湊識別內容,使內容不可變可驗證。如果檔案中只變更一個位元組,CID 就會完全改變。

為什麼內容定址很重要

傳統 web 架構依賴基於位置的定址。當你訪問 https://example.com/image.jpg 時,你信任:

  1. 域名擁有者沒有更改內容
  2. 伺服器在線且可訪問
  3. 內容沒有被竄改

使用 CIDs 進行內容定址:

  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 CIDs 總是以 Qm 開頭,看起來像:

QmYwAPJzv5CZsnA625s3Xf2nemtYgPpHdWEz79ojWnPbdG

特性:

  • 僅 Base58 編碼
  • 僅 SHA-256 雜湊函數
  • 僅 DAG-PB(Protobuf)編解碼器
  • 46 個字元長
  • 與所有 IPFS 實作向後相容

何時使用 CIDv0:

  • 與舊 IPFS 節點的最大相容性
  • 與期望 Qm 前綴的現有系統合作
  • 檔案儲存(最常見的用例)

CIDv1:現代標準

CIDv1 CIDs 更靈活,可能看起來像:

bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi  # Base32
zb2rhj7crUKTQYRGCRATFaQ6YFLTde2YzdqbbhAASkL9uRDXn      # Base58
f01551220d1e2c35...                                      # Base16

特性:

  • 多種編碼格式(Base32、Base58、Base16)
  • 支援不同雜湊函數(SHA-256、SHA-512、BLAKE2 等)
  • 多種編解碼器(Raw、DAG-CBOR、DAG-JSON 等)
  • 自描述格式
  • 使用 Base32 時不區分大小寫

何時使用 CIDv1:

  • 構建新應用
  • 需要不區分大小寫的識別碼
  • 處理結構化資料(JSON、CBOR)
  • 使用替代雜湊函數

版本之間的轉換

你可以在版本之間轉換 CIDs,同時保持相同的內容引用:

// 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...)

實用範例:使用 CIDs

讓我們探索如何使用 IPFS Ninja API 在實踐中使用 CIDs:

上傳內容並取得 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. 永遠驗證 CIDs

在你的應用中使用 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 映射

如果你經常產生 CIDs,考慮快取:

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 元資料儲存

使用 CIDs 不可變地儲存 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. 內容分發

使用 CIDs 進行分散式內容交付:

// 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 };
};

使用 CIDs 理解 IPFS 釘選

CIDs 預設是臨時的——它們必須被「釘選」才能保持可用。在我們關於什麼是 IPFS 釘選 的完整指南中了解更多關於這個關鍵概念。

選擇 IPFS 釘選服務時,考慮閱讀我們的 IPFS Ninja vs Pinata 比較或探索我們對今天可用的最佳 IPFS 釘選服務 的綜述。

在 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 教學

結論

CIDs 是 IPFS 內容定址系統的基礎,提供不可變、可驗證和去中心化的內容識別。理解它們如何運作——從 CIDv0 vs CIDv1 的技術細節到實際的實作模式——對於構建強大的去中心化應用至關重要。

關鍵要點:

  • CIDs 唯一識別內容,而非位置
  • CIDv0 提供最大相容性,CIDv1 提供靈活性
  • 內容定址實現驗證和去重
  • 正確的 CID 處理對生產應用至關重要

無論你是儲存 NFT 元資料、部署去中心化網站,還是構建內容分發系統,CIDs 都提供你真正去中心化應用所需的可靠基礎。

準備好開始釘選了嗎? 建立免費帳戶 —— 50 個檔案、1 GB 儲存、2 GB 頻寬/月。無需信用卡。

返回部落格