# Web3 应用调用 IPFS 服务实现文件去中心化存储

By [Blue](https://paragraph.com/@blue-9) · 2023-12-27

---

> 在`Web3`应用中，有一个很重要的功能就是存储文件，在传统的`Web2`应用开发中，我们一般会把文件存储在`服务器`或`OSS`中，在`Web3`我们一般把文件存储在`IPFS`服务中，`IPFS`服务可以实现文件的去中心化存储，这篇文章主要讲讲`Web3`应用中如何使用`IPFS`服务来存储文件。

### 一、关于 IPFS

`IPFS`是一种点对点的超媒体协议，即一个实现文件去中心化存储的协议，通过`IPFS`可以将文件分解为很多区块并存储在多个提供存储服务的服务器上，和我们`Web3`去中心化的概念一样，所以我们在`Web3`应用中文件存储一般也是使用`IPFS`。

提供`IPFS`的服务商很多：

*   [Pinata](https://www.pinata.cloud/): `Pinata`是一个去中心化的文件存储平台，为开发人员和企业提供了稳定、安全、高效的文件存储和分发服务。
    
*   [nft.storage](https://nft.storage/): `nft.storage`是一个专门针对`NFT`存储的去中心化平台，为开发人员和企业提供了安全、高效的NFT存储服务。
    
*   [web3.storage](https://web3.storage/): `Web3.storage`是用于与`IPFS`网络和`Filecoin`区块链互动的网关的另一次迭代。
    

这次我们选择`Pinata`来实现`IPFS`上传的操作，选择其他服务商，如`Web3.storage`操作也是类似。

### 二、`Pinata` 服务申请`Gateway`及`API Key`

首先需要去`Pinata`官网申请一下`Gateway`和`API Key`。`Gateway`是用于最后我们展示图片路径前缀，`API Key`用于在`Web3`应用前端中调用`Pinata`的文件上传服务。

![image.png](https://storage.googleapis.com/papyrus_images/995ee995906d027c8dd9a244c53c2834800880c685fd9fc77c5ec3be997cc9c8.webp)

image.png

![image.png](https://storage.googleapis.com/papyrus_images/1b1c0ea9ad377d25c51d57420d068401ab0ead6b3d2f69e2ed04242294535725.png)

image.png

### 三、编写链端服务

这里我写了一个简单的链端服务，来`新增`和`查询`任务。

    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.19;
    
    contract List {
        struct Task {
            uint id;
            string name;
            string ipfsHash;
            address owner;
        }
    
        Task[] private list;
    
        function createTask(string calldata name, string calldata ipfsHash) public {
            uint taskId = list.length;
            list.push(Task(
                taskId,
                name,
                ipfsHash,
                msg.sender
            ));
        }
    
        function getTask() public view returns (Task[] memory) {
            Task[] memory temporary = new TaskUnsupported embed;
            uint counter = 0;
            for (uint i = 0; i < list.length; i++) {
                if (list[i].owner == msg.sender) {
                    temporary[counter] = list[i];
                    counter++;
                }
            }
            Task[] memory result = new TaskUnsupported embed;
            for (uint i = 0; i < counter; i++) {
                result[i] = temporary[i];
            }
            return result;
        }
    }
    

其中的`ipfsHash`字段就是用于前端上传文件到`IPFS`后，`Pinata`返回的`Hash`字段，最终要展示图片也是用这个`Hash`值和之前我们申请的`Gateway`拼接展示。

### 四、前端调用`IPFS`服务上传图片

    const axios = require('axios')
    const FormData = require('form-data')
    const fs = require('fs')
    const JWT = 'PINATA_IPFS_API_KEY'
    
    const pinFileToIPFS = async () => {
        const formData = new FormData();
        const src = "2.jpg";
    
        const file = fs.createReadStream(src)
        formData.append('file', file)
    
        const pinataMetadata = JSON.stringify({
            name: 'testjpg',
        });
        formData.append('pinataMetadata', pinataMetadata);
    
        const pinataOptions = JSON.stringify({
            cidVersion: 0,
        })
        formData.append('pinataOptions', pinataOptions);
    
        try{
            const res = await axios.post("https://api.pinata.cloud/pinning/pinFileToIPFS", formData, {
                maxBodyLength: "Infinity",
                headers: {
                    'Content-Type': `multipart/form-data; boundary=${formData._boundary}`,
                    'Authorization': `Bearer ${JWT}`
                }
            });
            console.log(res.data);
        } catch (error) {
            console.log(error);
        }
    }
    pinFileToIPFS()
    

前端主要`axios`去调用`Pinata`提供的`IPFS`上传接口上传文件，上传成功后在`res.data`中会响应一个`IpfsHash`字段，我们再把这个字段提供给智能合约存储即可。

最后在前端展示图片时通过`https://<your-gateway-domain>/ipfs/<IpfsHash>`拼接展示即可。

具体文档也可参考`Pinata`官网文档：[点此查看](https://docs.pinata.cloud/docs/getting-started)

### 五、案例及源码

这个我写一个完整的案例，源码也开源给大家参考：

*   案例演示：[点此查看](https://ipfs-pinata-frontend.vercel.app/)
    
*   链端源码：[点此查看](https://github.com/junkaione/ipfs-pinata-server)
    
*   前端源码：[点此查看](https://github.com/junkaione/ipfs-pinata-frontend)
    

> 到此就实现了在`Web3`应用中通过`Pinata`提供的`IPFS`服务实现上传文件的操作，希望各位小伙伴给我多多点赞、收藏哦~

---

*Originally published on [Blue](https://paragraph.com/@blue-9/web3-ipfs)*
