IPFS 简介
January 13th, 2023

简介

星际文件系统InterPlanetary File System,缩写为IPFS)是一个旨在实现文件的分布式存储、共享和持久化的网络传输协议。它是一种内容可寻址的对等超媒体分发协议。在IPFS网络中的节点构成一个分布式文件系统

主要有以下几个特点

  • 支持弹性网络:在传统的互联网中,文件是存储在中心化服务器上的,假如你的文件服务器宕机了。就会导致文件不可访问。但在IPFS中,你还可以从其他节点获取文件。

  • 内容审核更困难:因为IPFS上的文件可以来自很多地方,所以任何人都更难封锁。

  • 更快的文件获取速度:由于你可以从附近的节点上获取文件。而不是其他更远的地方,所以大大提升了访问速度。(类似于CDN)

今天的万维网是以所有权和访问权为结构的,这意味着你要想从拥有者那里获得文件,必须要先获得访问权。但IPFS是基于占有和参与的理念的,即人们拥有着彼此的文件并参与提供文件。

IPFS只有在人们积极参与的情况下才能更好的运转。如果你用你的电脑使用IPFS共享文件,但后来你关闭了,其他人就不能再从你那里获得文件。但是,如果文件的副本存储在其他运行着IPFS的计算机上,则这些文件就可以做出共享。

工作原理

IPFS遵循了三个基本原则

  • 通过内容寻址来进行唯一的标识

    一般情况下文件的路径是基于位置,无论是你本地的文件 /Users/..../code.js 还是网络上可访问的文件 http://www.google.com/index.html

    IPFS 的文件路径不是基于地址的,而是基于文件内容。IPFS会基于文件内容生成一个加密的哈希值,这个值用来作为路径的一部分,如下面地址中 ipfs/ 后面的内容

    /ipfs/QmcuLr8xuHm6ViSYuppjDxCXE8vDuUBKmdAwcrTJRRnEUY
    

    IPFS 使用内容寻址,即通过内容而不是通过它的位置来定位文件。每个使用 IPFS 协议的文件都有一个内容标识符,即 CID,也就是它的哈希值。这个哈希值对于文件来说是独一无二的。

  • 通过有向无环图(DAG)进行内容链接

    IPFS和许多其他分布式系统一样使用了一种称为有向无环图(DAG)的数据结构。具体来说,是使用了默克尔有向无环图(Merkle DAG)。

    为了建立一个Merkle DAG表示你的文件,IPFS通常首先将文件分块。(分块意味着文件的不同部分可以有不同的来源,并被快速验证)。分块的内容会经过哈希运算得到一个哈希值作为CID,并作为 Merkle DAG 的节点。 这些节点再次经过哈希运算也就得到了该文件的CID

    同样,如果文件处于文件夹内,则也会根据文件夹内的文件内容经过哈希运算得到文件夹的CID

    如果你有两个类似的文件,文件分块后的生成的CID 如果有相同的,则可以引用相同的数据子集,可以很好的达到去重的效果。

    例如,更新文件时,更新的文件和未更新文件的第一个块的CID相同,则可以引用相同的块。而不是重新创建。

    因此,概括地说,IPFS让你为内容赋予 CID,并将这些内容连接在Merkle DAG中。

  • 通过分布式哈希表(DHT) 发现内容

    DHT的最主要思想是全网维护一个巨大的文件索引哈希表,这个哈希表的条目形如<Key,Value>。其中,Key通常是文件的某个哈希算法下的哈希值(也可以是文件名或者文件内容描述) ,而Value则是存储文件的IP地址。查询时,仅需要提供Key,就能从表中查询到存储节点的地址。

    由于这个哈希表很大,因此它会被分割成小块,按照一定的算法和规则分布到全网各个节点上。
    每个节点仅需要维护一小块哈希表,但每块哈希表不止由一个节点维护(这样即使节点意外挂掉也有其他的节点使DHT可用)

    当节点接受到查询请求后,如果可以在自己的桶(每一个节点维护的DHT子集被称为”桶“)中找到则回复,否则联系最近节点回复。这个过程一直到找到目标节点为止。

这三个原则相互依存,实现IPFS的生态系统。

使用

命令行使用

命令行安装 js-ipfs

$ npm install -g ipfs

也可以安装客户端 https://ipfs.tech/#install

初始化ipfs仓库

$ jsipfs init
initializing ipfs node at .jsipfs

启动本地 ipfs 网络实例

$ jsipfs daemon
Initializing IPFS daemon...
HTTP API listening on /ip4/127.0.0.1/tcp/5002/http
gRPC listening on /ip4/127.0.0.1/tcp/5003/ws
Gateway (read only) listening on /ip4/127.0.0.1/tcp/9090/http
Web UI available at http://127.0.0.1:5002/webui
Daemon is ready

添加文件

$ jsipfs add util.ts
added QmbFMke1KXqnYyBBWxB74N4c5SBnJMVAiMNRcGu6x1AwQH util.ts

访问文件内容

$ jsipfs cat QmbFMke1KXqnYyBBWxB74N4c5SBnJMVAiMNRcGu6x1AwQH

API使用

首先需要一个可以公网访问的服务器作为 ipfs 节点。可以选择自己的公网服务器或者 infura 服务。这里就以 infura 为例,而且其还有着5G的免费空间可以使用。在 infura 上创建 ipfs 项目后会有一个 projectIdprojectSecret

安装

项目中安装 ipfs-http-client

$ yarn add ipfs-http-client

初始化

import { create, urlSource, CID } from 'ipfs-http-client'
import fs from 'node:fs'

const projectId = 'xxxxxx'
const projectSecret = 'xxxxxx'

const auth = 'Basic ' + Buffer.from(projectId + ':' + projectSecret).toString('base64')

const ipfs = create({
  host: 'ipfs.infura.io',
  port: 5001,
  protocol: 'https',
  headers: {
    authorization: auth
  }
})

上传资源

const upload = async () => {
  // 上传本地文件 或 网络资源 或 文本
  
  // 1. 本地资源
  const file = fs.readFileSync('./test.sol', 'utf-8')
  // 2. 网络资源
  //const file = urlSource('https://www.baidu.com/img/PCfb_5bf082d29588c07f842ccde3f97243ea.png')
  // 3. 文本
  // const file = 'hello world'

  const result = await ipfs.add(file)

  console.log(result)
}
upload()

上传成功后会返回如下格式的内容

{
  path: 'QmNvHxnJQ6Ho9LWw1FwCn3nqcJXSeM76cmmd6JvoLEzW8Q',
  cid: CID(QmNvHxnJQ6Ho9LWw1FwCn3nqcJXSeM76cmmd6JvoLEzW8Q),
  size: 593
}

通过浏览器的地址 https://ipfs.infura.io/ipfs/${path},即可访问内容

读取资源

const cat = async () => {
  const decoder = new TextDecoder();
  let content = '';
  for await (const chunk of ipfs.cat('QmNvHxnJQ6Ho9LWw1FwCn3nqcJXSeM76cmmd6JvoLEzW8Q')) {
    content += decoder.decode(chunk);
  }
  console.log(content)
}
Subscribe to 0xB483…3cD2
Receive the latest updates directly to your inbox.
Mint this entry as an NFT to add it to your collection.
Verification
This entry has been permanently stored onchain and signed by its creator.
More from 0xB483…3cD2

Skeleton

Skeleton

Skeleton