· Nacho Coll · Tutorials  · 14 分钟阅读

如何在 2026 年将文件上传到 IPFS — 完整指南

了解如何使用仪表板、REST API、JavaScript 或 Python 将 JSON、图片、PDF 和任何文件上传到 IPFS。带代码示例的分步指南。

了解如何使用仪表板、REST API、JavaScript 或 Python 将 JSON、图片、PDF 和任何文件上传到 IPFS。带代码示例的分步指南。

如何在 2026 年将文件上传到 IPFS — 完整指南

如果您曾经希望以一种没有任何单一公司可以控制、任何人都可以验证、并且抵抗审查的方式存储文件,那么星际文件系统(InterPlanetary File System,IPFS)就是答案。本指南将引导您了解将文件上传到 IPFS 的每一种实用方法——从简单的拖放仪表板到 JavaScript 和 Python 中可用于生产的代码。

带有拖放文件上传的 IPFS Ninja 上传页面

什么是 IPFS,为什么要使用它?

IPFS 是一种用于存储和共享文件的对等协议。IPFS 不是按内容所在的位置(特定服务器上的 URL)来寻址内容,而是按内容是什么来寻址。每个文件都会获得一个独特的内容标识符(CID),该标识符源自其内容的加密哈希。这种设计为您提供了传统托管无法匹敌的三个特性:

  • 内容寻址。CID 保证您收到的数据正是上传的数据。如果有一个字节发生变化,CID 就会变化。任何人都无法在不使其地址失效的情况下篡改您的文件。
  • 永久性。只要网络上至少有一个节点固定(pin)了您的文件,它就会保持可用。像 IPFS Ninja 这样的固定服务可以确保您的文件保持在线,而无需您运行自己的基础设施。要了解为什么固定很重要以及垃圾回收的工作原理,请参阅什么是 IPFS 固定?
  • 抗审查。IPFS 上的文件不绑定到单个域名或服务器。没有政府或公司可以关闭的单点故障。

常见的用例包括 NFT 元数据和媒体、去中心化应用程序资产、科学数据集、公共记录,以及任何数据完整性至关重要的场景。

前提条件

在上传任何内容之前,您需要两样东西:

  1. 一个 IPFS Ninja 账户。在 https://ipfs.ninja/signup 免费注册。免费计划为您提供 500 个文件和 1 GB 的存储空间——绰绰有余足以开始。

  2. 一个 API 密钥。登录后,进入仪表板中的 API Keys 部分并生成一个新密钥。它看起来像 bws_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6(前缀 bws_a1b2c3d4 显示在仪表板中以便识别)。请保密此密钥。您需要在每个 API 请求中将其传递到 X-Api-Key 标头中。

如果您只想使用 Web 仪表板,可以跳过 API 密钥步骤,但拥有 API 密钥可以让您从自己的应用程序中进行编程上传。

方法 1:Web 仪表板(拖放)

上传文件最快的方法是通过 IPFS Ninja 仪表板。

  1. 导航到 https://ipfs.ninja/upload 并登录。
  2. 将任何文件——JSON、PNG、JPEG、PDF、SVG 或任何其他类型——拖放到上传区域,或点击浏览文件系统。
  3. 可选添加描述元数据(键值对)以帮助您稍后整理文件。
  4. 点击上传。几秒钟内,您的文件就会被固定到 IPFS,您将收到一个 CID 和一个网关 URL。

此方法支持任何文件类型,无需代码。它非常适合一次性上传、快速测试或需要固定内容的非技术团队成员。

方法 2:使用 curl 的 REST API

对于自动化和脚本,REST API 是最直接的方法。端点为:

POST https://api.ipfs.ninja/upload/new

每个请求都需要 X-Api-Key 标头和带有 content 字段的 JSON 主体。

上传 JSON

要上传 JSON 对象,请直接将其作为 content 的值传递:

curl -X POST https://api.ipfs.ninja/upload/new \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: bws_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6" \
  -d '{
    "content": {
      "name": "Astro Cat #42",
      "description": "A fearless cat exploring the cosmos.",
      "image": "ipfs://bafkreigh2akiscaildc7lqnpfuh3sksq4ogrtz7tpk2aulid5fhqotmqm",
      "attributes": [
        { "trait_type": "Background", "value": "Nebula" },
        { "trait_type": "Helmet", "value": "Gold" }
      ]
    },
    "description": "NFT metadata for Astro Cat #42",
    "metadata": { "collection": "astro-cats", "tokenId": "42" }
  }'

descriptionmetadata 字段是可选的。它们与您的文件一起存储在 IPFS Ninja 仪表板和 API 响应中,以帮助您稍后识别和过滤上传。它们不包含在固定到 IPFS 的内容中。

上传图片(二进制文件)

对于图片或 PDF 等二进制文件,请对文件进行 base64 编码,并将编码后的字符串作为 content 传递:

curl -X POST https://api.ipfs.ninja/upload/new \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: bws_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6" \
  -d "{
    \"content\": \"$(base64 -w 0 photo.png)\",
    \"description\": \"Product photo for landing page\",
    \"metadata\": { \"project\": \"website-redesign\" }
  }"

API 会自动检测内容类型。无需指定您要上传的是 JSON、图片还是 PDF——服务会为您处理。

方法 3:JavaScript / Node.js

使用内置的 fetch API(Node.js 18+ 或任何现代浏览器),上传到 IPFS 只需几行代码。

上传 JSON

const API_KEY = "bws_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6";

const metadata = {
  name: "Astro Cat #42",
  description: "A fearless cat exploring the cosmos.",
  image: "ipfs://bafkreigh2akiscaildc7lqnpfuh3sksq4ogrtz7tpk2aulid5fhqotmqm",
  attributes: [
    { trait_type: "Background", value: "Nebula" },
    { trait_type: "Helmet", value: "Gold" },
  ],
};

const response = await fetch("https://api.ipfs.ninja/upload/new", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "X-Api-Key": API_KEY,
  },
  body: JSON.stringify({
    content: metadata,
    description: "NFT metadata for Astro Cat #42",
  }),
});

const result = await response.json();
console.log("CID:", result.cid);
console.log("Gateway URL:", result.uris.url);

上传二进制文件

import { readFileSync } from "node:fs";

const API_KEY = "bws_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6";
const fileBuffer = readFileSync("photo.png");
const base64Content = fileBuffer.toString("base64");

const response = await fetch("https://api.ipfs.ninja/upload/new", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "X-Api-Key": API_KEY,
  },
  body: JSON.stringify({
    content: base64Content,
    description: "Product photo",
    metadata: { project: "website-redesign" },
  }),
});

const result = await response.json();
console.log("CID:", result.cid);
console.log("IPFS URI:", result.uris.ipfs);
console.log("Gateway URL:", result.uris.url);

带错误处理的批量上传

在生产环境中,您经常需要上传许多文件。这是一个带有重试的可重用助手:

import { readFileSync } from "node:fs";

const API_KEY = "bws_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6";
const API_URL = "https://api.ipfs.ninja/upload/new";

async function uploadToIPFS(content, options = {}) {
  const body = { content };
  if (options.description) body.description = options.description;
  if (options.metadata) body.metadata = options.metadata;

  const response = await fetch(API_URL, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "X-Api-Key": API_KEY,
    },
    body: JSON.stringify(body),
  });

  if (!response.ok) {
    const error = await response.text();
    throw new Error(`Upload failed (${response.status}): ${error}`);
  }

  return response.json();
}

// Upload JSON
const jsonResult = await uploadToIPFS(
  { name: "My Data", values: [1, 2, 3] },
  { description: "Sample dataset" }
);

// Upload image
const imageBase64 = readFileSync("banner.jpg").toString("base64");
const imageResult = await uploadToIPFS(imageBase64, {
  description: "Banner image",
  metadata: { format: "jpg", width: "1200" },
});

console.log("JSON CID:", jsonResult.cid);
console.log("Image CID:", imageResult.cid);

方法 4:Python

Python 的 requests 库使 IPFS 上传变得简单。

上传 JSON

import requests

API_KEY = "bws_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6"
API_URL = "https://api.ipfs.ninja/upload/new"

headers = {
    "Content-Type": "application/json",
    "X-Api-Key": API_KEY,
}

payload = {
    "content": {
        "name": "Astro Cat #42",
        "description": "A fearless cat exploring the cosmos.",
        "image": "ipfs://bafkreigh2akiscaildc7lqnpfuh3sksq4ogrtz7tpk2aulid5fhqotmqm",
        "attributes": [
            {"trait_type": "Background", "value": "Nebula"},
            {"trait_type": "Helmet", "value": "Gold"},
        ],
    },
    "description": "NFT metadata for Astro Cat #42",
    "metadata": {"collection": "astro-cats", "tokenId": "42"},
}

response = requests.post(API_URL, json=payload, headers=headers)
result = response.json()

print(f"CID: {result['cid']}")
print(f"Gateway URL: {result['uris']['url']}")

上传二进制文件

import base64
import requests

API_KEY = "bws_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6"
API_URL = "https://api.ipfs.ninja/upload/new"

headers = {
    "Content-Type": "application/json",
    "X-Api-Key": API_KEY,
}

with open("photo.png", "rb") as f:
    encoded = base64.b64encode(f.read()).decode("utf-8")

payload = {
    "content": encoded,
    "description": "Product photo",
    "metadata": {"project": "website-redesign"},
}

response = requests.post(API_URL, json=payload, headers=headers)
result = response.json()

print(f"CID: {result['cid']}")
print(f"Size: {result['sizeMB']} MB")
print(f"IPFS URI: {result['uris']['ipfs']}")
print(f"Gateway URL: {result['uris']['url']}")

批量上传

import base64
from pathlib import Path
import requests

API_KEY = "bws_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6"
API_URL = "https://api.ipfs.ninja/upload/new"
HEADERS = {"Content-Type": "application/json", "X-Api-Key": API_KEY}


def upload_file(file_path, description=None, metadata=None):
    with open(file_path, "rb") as f:
        encoded = base64.b64encode(f.read()).decode("utf-8")

    payload = {"content": encoded}
    if description:
        payload["description"] = description
    if metadata:
        payload["metadata"] = metadata

    response = requests.post(API_URL, json=payload, headers=HEADERS)
    response.raise_for_status()
    return response.json()


# Upload all PNGs in a directory
for png in Path("./images").glob("*.png"):
    result = upload_file(png, description=f"Image: {png.name}")
    print(f"{png.name} -> {result['cid']}")

理解响应

每次成功上传都会返回一个 JSON 对象,其字段如下:

{
  "cid": "bafkreigh2akiscaildc7lqnpfuh3sksq4ogrtz7tpk2aulid5fhqotmqm",
  "sizeMB": 0.024,
  "uris": {
    "ipfs": "ipfs://bafkreigh2akiscaildc7lqnpfuh3sksq4ogrtz7tpk2aulid5fhqotmqm",
    "url": "https://ipfs.ninja/ipfs/bafkreigh2akiscaildc7lqnpfuh3sksq4ogrtz7tpk2aulid5fhqotmqm"
  }
}
字段描述
cid内容标识符——您文件内容的唯一哈希。这是您文件在 IPFS 上的永久地址。
sizeMB已上传文件的大小(以兆字节为单位)。
uris.ipfsIPFS 原生 URI(ipfs://CID)。从智能合约、NFT 元数据或其他 IPFS 感知应用程序引用文件时使用此项。
uris.url您可以在任何浏览器中打开的直接 HTTPS 网关 URL。非常适合共享、嵌入到网站或快速验证。

访问您的文件

文件固定后,有两种主要的检索方式。

专用网关

每个 IPFS Ninja 账户都包括一个带有自定义 slug 的专用网关:

https://your-slug.gw.ipfs.ninja/ipfs/{CID}

专用网关比公共网关更快、更可靠,因为它们直接连接到 IPFS Ninja 固定基础设施。您可以使用上传响应中的 CID 通过您的专用网关访问您的文件。

公共 IPFS 网关

任何 IPFS 网关都可以使用 CID 提供您的内容:

https://ipfs.ninja/ipfs/{CID}     ← 您的专用网关
https://dweb.link/ipfs/{CID}       ← 公共网关
https://w3s.link/ipfs/{CID}        ← 公共网关

当您想要验证您的内容是否可以从 IPFS Ninja 网络外部访问时,公共网关非常有用。请记住,与您的专用网关相比,它们可能更慢或受到速率限制。

从智能合约和 dApp

在链上存储引用时(例如在 ERC-721 令牌 URI 中),使用 ipfs:// URI:

ipfs://bafkreigh2akiscaildc7lqnpfuh3sksq4ogrtz7tpk2aulid5fhqotmqm

钱包、市场和其他 IPFS 感知应用程序知道如何通过任何可用的网关解析此 URI。

最佳实践

将单个文件保持在 100 MB 以下。虽然 API 接受较大的上传,但较小的文件固定更快,并在 IPFS 网络上更有效地复制。如果您要处理大型数据集,请将它们拆分为较小的块。

使用描述性元数据descriptionmetadata 字段是免费的,并且使您稍后更容易管理上传。包括项目名称、版本号或任何有助于您搜索和过滤的标识符。

在您自己的数据库中存储 CID。即使 IPFS Ninja 存储您的上传历史记录,维护您自己的 CID 到应用程序级标识符(用户 ID、订单号、令牌 ID)的映射也使您的集成更具弹性。

在链上引用中使用 IPFS URI。在智能合约或不可变记录中始终存储 ipfs://CID 而不是 HTTPS 网关 URL。网关 URL 可能会改变;CID 不会。

对于结构化数据,首选 JSON 内容。当您的数据是结构化的(元数据、配置、记录)时,请将其作为 JSON 对象传递,而不是将其编码为字符串。API 存储得更有效,并且生成的 IPFS 内容是人类可读的。

优雅地处理错误。检查 HTTP 状态码并对 5xx 响应实施带有指数退避的重试。API 为 4xx 响应(无效的 API 密钥、缺少内容、信用不足)返回明确的错误消息,您应该将这些消息呈现给用户。

结论

将文件上传到 IPFS 从未如此简单。无论您喜欢可视化仪表板、快速 curl 命令,还是 JavaScript 或 Python 中的生产级集成,IPFS Ninja 都为您提供单一端点和跨所有内容类型的一致体验。

免费的 Dharma 计划包括 50 个文件、1 GB 存储空间和每月 2 GB 带宽——足以端到端构建和测试您的集成。当您准备扩展时,Bodhi 计划每月 5 美元、Karma 计划每月 19 美元和 Nirvana 计划每月 59 美元提供更高的限制、专用网关,以及(Nirvana 上的)优先支持。

创建您的免费账户 并在不到一分钟内开始将文件上传到 IPFS。

要深入了解带有签名令牌和客户端上传的 API,请参阅我们的 IPFS 上传 API 教程。有关包括列出文件、管理 API 密钥和配置网关的完整 API 参考,请访问文档

返回博客