跳到主要内容

IPFS 简介

· 阅读需 9 分钟

官网

简介

星际文件系统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)
}