簡介#
星際文件系統(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
項目後會有一個 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)
}