# IPFS 简介

By [Untitled](https://paragraph.com/@0xb483169fb514727aa8cc68ffcf8e43c254f83cd2) · 2023-01-13

---

[https://ipfs.tech](https://ipfs.tech)

简介
--

**星际文件系统**（**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](https://github.com/ipfs/js-ipfs)

    $ npm install -g ipfs
    

> 也可以安装客户端 [https://ipfs.tech/#install](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](https://infura.io/) 服务。这里就以 `infura` 为例，而且其还有着5G的免费空间可以使用。在 `infura` 上创建 `ipfs` 项目后会有一个 `projectId` 和 `projectSecret`

#### 安装

项目中安装 `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)
    }

---

*Originally published on [Untitled](https://paragraph.com/@0xb483169fb514727aa8cc68ffcf8e43c254f83cd2/ipfs)*
