目录

IPFS 内容定位

内容定位和CID

要深入了解内容标识符 (CID) 的构造方式, 请查看 ProtoSchool 的CID剖析教程.

内容标识符(CID)是用于指向 IPFS 中数据的标签。它不指示内容的存储位置,而是根据内容本身生成一种地址。无论内容的长度有多长,CID 都很短。

CID 是基于内容的 加密哈希值。那意味着:

  • 内容的任何差异都会产生不同的CID,同时:
  • 使用相同的配置,将相同内容添加到两个不同的 IPFS 节点时,也会产生相同的CID。

IPFS 默认使用 sha-256 哈希算法, 但是也支持很多不同的哈希算法. Multihash 项目展示了这些算法, 目的是满足未来应用程序对哈希的使用,并允许多个哈希函数共存。 (如果您对IPFS如何选择哈希类型感到好奇,您可以关注论坛讨论)。

标识格式

CID 可以具有不同的编码格式或 CID 版本,形成不同的展示格式。尽管现在“files”可变文件系统和对象操作默认使用 CIDV1版本,但是许多现有的 IPFS 工具仍会生成 v0版本的 CID,

版本 0 (v0)

在首次设计IPFS时,我们使用 58-encoded multihashes 作为CID(内容标识符)。这种方法比新版本CID更简单,但灵活性要低得多。默认情况下,CIDv0 仍用于许多 IPFS 操作,因此你通常需要支持 v0。

如果一个 CID 是以"Qm"开头的 46 字符长度的字符串, 那么它就是 CIDv0 版本的。(点击 decoding algorithm的 CID 规范以获取更多信息)

版本 1 (v1)

CID v1 包含一些前导符和内容哈希本身。前导符可以准确说明采用的表示格式。前导符包括:

  • 一个 multibase 前缀, 指定 CID 其余部分的编码方式
  • 一个 CID 版本标识, 指示 CID 的版本。
  • 一个 multicodec 标识符, 指示目标内容的格式:它可以帮助人们和软件知道在获取内容后如何解析该内容。

这些前导符还提供向前兼容性,支持在的未来CID版本中使用不同格式。

您可以使用 CID 的前几个字节来解释 CID 的其余部分,并知道如何在从 IPFS 获取后解码内容。有关更多详细信息,请查阅 CID 规格. 它包含解码算法 和 CID 解析代码的链接.

如果无法在 CIDv0 和 CIDv1 之间做出选择,请考虑通过传递版本标志(ipfs add --cid-version 1)为新项目选择 CIDv1。这更符合未来发展的要求, 而且可在浏览器环境中安全使用.

IPFS 项目将在不久的将来切换到 CIDv1 作为默认值。

CID 查看器

解析CID是很容易的。想要解析特定 CID 的multibase、multicodec或multihash信息?您可以使用CID 查看器https://cid.ipfs.io 或者IPLD 浏览器的 CID 信息面板 对不同格式的 CID 进行查看分析。

下面有 2 个示例 CID 的解析链接:

访问 ProtoSchool的CID 剖析教程,了解如何对一个文件生成多个版本的 CID。

CID 转换

通过将 CID 从 v0 转换为 v1,可以将其使用不同编码方式来进行编码。

CIDv1 的默认值是不区分大小写的 base32,但建议对 IPNS 名称使用较短的base36 ,以确保在 [子域](https://docs.ipfs.io/how-to/address-ipfs-on-web/#subdomain-gateway) 上使用相同的文本表示形式。

v0 to v1

内置的 ipfs cid format 命令可以在命令行里执行转换:

1
2
$ ipfs cid format -v 1 -b base32 QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR
bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi

JavaScript 用户也可以使用cids库提供的 toV1() 方法:

1
2
3
const CID = require('cids')
new CID('QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR').toV1().toString('base32')
// → bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi

文本转二进制

CID 既可以表示为文本,也可以表示为二进制。当考虑速度和存储效率时,后者可能是更好的选择。

要将 CIDv1 从文本转换为二进制形式,只需去掉第一个字符,然后使用multibase 表规范对剩余的内容进行解析。

JS 可以使用 cids 库提供的 Uint8Array函数:

1
2
3
const CID = require('cids')
new CID('bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi').bytes
// → Uint8Array [ 1, 112,  18,  32, 195, 196, 115,  62, ... ]

请注意正确解析 CID。不要截取CID 的固定长度进行使用 除非您是将数据导入 IPFS 的人,否则CID的长度不是确定性的,其取决于其中 multihash 的长度。 为了说明这一点,传递自定义哈希函数将生成不同长度的 CID:

1
2
3
4
5
6
$ ipfs add --cid-version 1 --hash sha2-256    -nq cat.jpg | wc -c
60
$ ipfs add --cid-version 1 --hash blake2b-256 -nq cat.jpg | wc -c
63
$ ipfs add --cid-version 1 --hash sha3-512    -nq cat.jpg | wc -c
111

CID 转十六进制

有时候, CID 的十六进制 hexadecimal 的表示方式有助于调试.

要把原始比特字节的整个 CID 转成十六进制表示, 可以使用内置的 base16 编码进行转换,然后移除头部的 f (multibase 前缀):

1
2
3
4
5
> cid.toString('base16')
'f01701220c3c4733ec8affd06cf9e9ff50ffc6bcd2ec85a6170004bb709669c31de94391a'

> cid.toString('base16').substring(1)
'01701220c3c4733ec8affd06cf9e9ff50ffc6bcd2ec85a6170004bb709669c31de94391a' // "cid as hex"

要从 16 进制转回 以’f’(小写 base16 格式multibase 前缀)开头、CIDv1格式的 CID,直接在前面加上’f’就就可以了,(比如 f01701220c3c4733ec8affd06cf9e9ff50ffc6bcd2ec85a6170004bb709669c31de94391a), 或者转换后使用 toString函数转换为其他编码格式:

1
2
> new CID('f' +'01701220c3c4733ec8affd06cf9e9ff50ffc6bcd2ec85a6170004bb709669c31de94391a').toString('base32')
// → bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi

提示 子域名网关 将具有自定义编码格式(如 base16)的路径转换为 base32 或 base36,以便将 CID 放入 DNS 标签中:

更多资源

查看以下链接,了解有关 CID 及其工作原理的更多信息: