Съхранение на NFT метаданни: IPFS ръководство за NFT
Ръководство стъпка по стъпка за съхранение на NFT метаданни в IPFS. Включва шаблони ERC-721 tokenURI, примери в Python и JavaScript.
Nacho founded IPFS.NINJA to make content-addressed storage feel as simple as an S3 PUT — a single API call, a permanent CID, no wallets or peer discovery to reason about.

- Съхранявайте NFT метаданните като неизменен, адресиран по съдържание JSON, така че tokenURI връзките никога да не остаряват.
- Качете първо изображението, след което вградете неговия CID в ERC-721 метаданните JSON преди закрепване.
- IPFS CID-ите защитават дългосрочната стойност на NFT дори ако оригиналната хостинг услуга изчезне.
- Криптографското хеширане гарантира целостта на NFT метаданните — всяка редакция произвежда различен CID.
Създаването на NFT изисква повече от просто разполагане на смарт контракт — необходимо ви е надеждно, децентрализирано съхранение за вашите метаданни и активи. Това изчерпателно ръководство ви води стъпка по стъпка през съхраняването на NFT метаданни в IPFS, използвайки най-добрите практики в индустрията, с пълни примери на код за разработчици на Python и JavaScript.

Защо IPFS за съхранение на NFT метаданни?#
Традиционният уеб хостинг създава рискове от централизация за NFT проектите. Когато метаданните живеят на конвенционални сървъри, NFT-тата могат да станат „счупени”, ако хостинг услугата падне или промени URL адресите. IPFS (InterPlanetary File System) решава това, като предоставя:
- Неизменно адресиране на съдържание: Всеки файл получава уникален Content Identifier (CID), който никога не се променя
- Децентрализирано съхранение: Съдържанието съществува в множество възли по целия свят
- Криптографска проверка: Целостта на файла е гарантирана чрез хеширане на съдържанието
- URL адреси, устойчиви на бъдещето: IPFS връзките работят неограничено, защитавайки дългосрочната стойност
За по-задълбочено разбиране на основите на IPFS, вижте нашето ръководство за това какво е IPFS pinning.
Разбиране на структурата на ERC-721 метаданните#
Стандартът ERC-721 определя как трябва да бъдат структурирани NFT метаданните. Функцията tokenURI на вашия смарт контракт връща URL, който сочи към JSON метаданни, следващи този шаблон:
{
"name": "My Amazing NFT #1",
"description": "A unique digital artwork showcasing...",
"image": "ipfs://QmYourImageCIDHere",
"attributes": [
{
"trait_type": "Background",
"value": "Blue"
},
{
"trait_type": "Rarity",
"value": "Common"
}
],
"external_url": "https://yourproject.com/token/1"
}Ключови полета на метаданните#
- name: Заглавието на NFT, показвано в портфейли и пазари
- description: Подробна информация за NFT
- image: IPFS URL към основния визуален актив
- attributes: Свойства, базирани на черти, за филтриране и изчисления на рядкост
- external_url: Незадължителна връзка към допълнително съдържание или уебсайт на вашия проект
Процес на съхранение на NFT в IPFS стъпка по стъпка#
Стъпка 1: Подгответе вашите активи и метаданни#
Преди да качите каквото и да е, организирайте вашите файлове:
- Основни активи: Изображения, видеоклипове или друго първично съдържание
- Файлове с метаданни: JSON файлове, описващи всеки NFT
- Метаданни на колекцията: Незадължителна информация на ниво колекция
Стъпка 2: Качете активи в IPFS#
Започнете с качване на вашите основни NFT активи (изображения, видеоклипове и т.н.), за да получите техните IPFS CID-ове. Ще се позовавате на тези CID-ове във вашите JSON файлове с метаданни.
Ето как да качите изображение, използвайки Python:
import requests
import base64
import json
def upload_image_to_ipfs(image_path, api_key):
"""Upload an image file to IPFS and return its CID"""
# Read and encode image
with open(image_path, 'rb') as f:
image_data = base64.b64encode(f.read()).decode('utf-8')
# Prepare upload payload
payload = {
"content": image_data,
"description": f"NFT Asset: {image_path}"
}
headers = {
"Content-Type": "application/json",
"X-Api-Key": api_key
}
# Upload to IPFS.NINJA
response = requests.post(
"https://api.ipfs.ninja/upload/new",
headers=headers,
json=payload
)
if response.status_code == 200:
result = response.json()
print(f"✅ Image uploaded successfully!")
print(f"CID: {result['cid']}")
print(f"IPFS URL: {result['uris']['ipfs']}")
print(f"Gateway URL: {result['uris']['url']}")
return result['cid']
else:
print(f"❌ Upload failed: {response.text}")
return None
# Example usage
API_KEY = "bws_1234567890abcdef1234567890abcdef" # Replace with your actual key
image_cid = upload_image_to_ipfs("my-nft-artwork.png", API_KEY)Стъпка 3: Създайте и качете JSON метаданни#
След като имате CID-овете на активите, създайте JSON файловете с метаданни и ги качете:
def create_and_upload_metadata(name, description, image_cid, attributes, api_key):
"""Create NFT metadata JSON and upload to IPFS"""
# Create metadata object
metadata = {
"name": name,
"description": description,
"image": f"ipfs://{image_cid}",
"attributes": attributes
}
# Convert to JSON string and encode
metadata_json = json.dumps(metadata, indent=2)
metadata_b64 = base64.b64encode(metadata_json.encode('utf-8')).decode('utf-8')
# Upload metadata
payload = {
"content": metadata_b64,
"description": f"NFT Metadata: {name}",
"metadata": {
"contentType": "application/json",
"nftTokenId": name.split('#')[1] if '#' in name else "1"
}
}
headers = {
"Content-Type": "application/json",
"X-Api-Key": api_key
}
response = requests.post(
"https://api.ipfs.ninja/upload/new",
headers=headers,
json=payload
)
if response.status_code == 200:
result = response.json()
print(f"✅ Metadata uploaded successfully!")
print(f"Metadata CID: {result['cid']}")
return result['cid']
else:
print(f"❌ Metadata upload failed: {response.text}")
return None
# Example usage
attributes = [
{"trait_type": "Background", "value": "Cosmic Blue"},
{"trait_type": "Eyes", "value": "Laser"},
{"trait_type": "Rarity", "value": "Epic"}
]
metadata_cid = create_and_upload_metadata(
name="Cosmic Warrior #001",
description="A fierce warrior from the distant galaxies, wielding the power of stars.",
image_cid=image_cid,
attributes=attributes,
api_key=API_KEY
)Стъпка 4: Имплементация в JavaScript#
За уеб приложения или Node.js проекти, ето еквивалента в JavaScript:
class NFTStorage {
constructor(apiKey) {
this.apiKey = apiKey;
this.baseUrl = 'https://api.ipfs.ninja';
}
async uploadFile(fileContent, description) {
const payload = {
content: fileContent, // base64 encoded
description: description
};
const response = await fetch(`${this.baseUrl}/upload/new`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Api-Key': this.apiKey
},
body: JSON.stringify(payload)
});
if (!response.ok) {
throw new Error(`Upload failed: ${response.statusText}`);
}
return await response.json();
}
async uploadImageFromFile(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = async (e) => {
try {
const base64Content = e.target.result.split(',')[1]; // Remove data:image/...;base64, prefix
const result = await this.uploadFile(base64Content, `NFT Image: ${file.name}`);
resolve(result.cid);
} catch (error) {
reject(error);
}
};
reader.readAsDataURL(file);
});
}
async uploadMetadata(name, description, imageCid, attributes = []) {
const metadata = {
name,
description,
image: `ipfs://${imageCid}`,
attributes
};
const metadataJson = JSON.stringify(metadata, null, 2);
const base64Metadata = btoa(metadataJson);
const result = await this.uploadFile(base64Metadata, `NFT Metadata: ${name}`);
return result.cid;
}
}
// Usage example
const storage = new NFTStorage('bws_1234567890abcdef1234567890abcdef'); // Replace with your key
// Upload process
async function createNFT() {
try {
// Assuming you have a file input element
const fileInput = document.getElementById('nft-image');
const imageFile = fileInput.files[0];
console.log('Uploading image...');
const imageCid = await storage.uploadImageFromFile(imageFile);
console.log(`Image uploaded: ${imageCid}`);
console.log('Uploading metadata...');
const metadataCid = await storage.uploadMetadata(
'Galaxy Explorer #042',
'A mysterious explorer traversing the cosmic void.',
imageCid,
[
{ trait_type: 'Class', value: 'Explorer' },
{ trait_type: 'Galaxy', value: 'Andromeda' },
{ trait_type: 'Rarity', value: 'Legendary' }
]
);
console.log(`Metadata uploaded: ${metadataCid}`);
console.log(`Token URI: ipfs://${metadataCid}`);
} catch (error) {
console.error('Upload failed:', error);
}
}Имплементиране на tokenURI във вашия смарт контракт#
След като вашите метаданни са качени в IPFS, имплементирайте функцията tokenURI във вашия ERC-721 контракт:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract MyNFTCollection is ERC721, Ownable {
mapping(uint256 => string) private _tokenURIs;
string private _baseTokenURI;
constructor(string memory name, string memory symbol) ERC721(name, symbol) {}
function setTokenURI(uint256 tokenId, string memory uri) external onlyOwner {
require(_exists(tokenId), "Token does not exist");
_tokenURIs[tokenId] = uri;
}
function setBaseURI(string memory baseURI) external onlyOwner {
_baseTokenURI = baseURI;
}
function tokenURI(uint256 tokenId) public view virtual override returns (string) {
require(_exists(tokenId), "Token does not exist");
string memory _tokenURI = _tokenURIs[tokenId];
// Return specific token URI if set
if (bytes(_tokenURI).length > 0) {
return _tokenURI;
}
// Fall back to base URI + token ID pattern
if (bytes(_baseTokenURI).length > 0) {
return string(abi.encodePacked(_baseTokenURI, tokenId.toString()));
}
return "";
}
function mintWithURI(address to, uint256 tokenId, string memory uri) external onlyOwner {
_mint(to, tokenId);
_tokenURIs[tokenId] = uri;
}
}Пакетни операции за големи колекции#
За големи NFT колекции пакетните операции спестяват време и разходи за gas:
def batch_upload_collection(collection_data, api_key):
"""Upload an entire NFT collection in batches"""
print(f"Starting batch upload of {len(collection_data)} NFTs...")
results = []
for i, nft_data in enumerate(collection_data):
print(f"Processing NFT {i+1}/{len(collection_data)}: {nft_data['name']}")
try:
# Upload image
image_cid = upload_image_to_ipfs(nft_data['image_path'], api_key)
if image_cid:
# Upload metadata
metadata_cid = create_and_upload_metadata(
name=nft_data['name'],
description=nft_data['description'],
image_cid=image_cid,
attributes=nft_data['attributes'],
api_key=api_key
)
if metadata_cid:
results.append({
'token_id': i + 1,
'name': nft_data['name'],
'image_cid': image_cid,
'metadata_cid': metadata_cid,
'token_uri': f"ipfs://{metadata_cid}"
})
except Exception as e:
print(f"❌ Error processing {nft_data['name']}: {e}")
print(f"✅ Batch upload complete! {len(results)} NFTs processed successfully.")
return results
# Example collection data
collection_data = [
{
'name': 'Cosmic Warrior #001',
'description': 'A fierce warrior from distant galaxies.',
'image_path': 'images/warrior_001.png',
'attributes': [
{'trait_type': 'Class', 'value': 'Warrior'},
{'trait_type': 'Rarity', 'value': 'Epic'}
]
},
# Add more NFTs...
]
results = batch_upload_collection(collection_data, API_KEY)Най-добри практики за съхранение на NFT метаданни#
1. Използвайте описателни имена на файлове#
При качване в IPFS използвайте смислени описания, за да помогнете с организацията:
payload = {
"content": base64_content,
"description": f"Collection: {collection_name} | Token: {token_id} | Type: {file_type}"
}2. Имплементирайте правилно обработване на грешки#
Винаги обработвайте неуспешни качвания елегантно:
import time
def upload_with_retry(upload_function, max_retries=3, delay=2):
"""Upload with exponential backoff retry logic"""
for attempt in range(max_retries):
try:
return upload_function()
except Exception as e:
if attempt == max_retries - 1:
raise e
print(f"Attempt {attempt + 1} failed: {e}. Retrying in {delay} seconds...")
time.sleep(delay)
delay *= 2 # Exponential backoff3. Валидирайте структурата на метаданните#
Уверете се, че вашите метаданни отговарят на стандартите:
def validate_metadata(metadata):
"""Validate NFT metadata structure"""
required_fields = ['name', 'description', 'image']
for field in required_fields:
if field not in metadata:
raise ValueError(f"Missing required field: {field}")
if not metadata['image'].startswith('ipfs://'):
raise ValueError("Image must be an IPFS URL")
if 'attributes' in metadata:
for attr in metadata['attributes']:
if 'trait_type' not in attr or 'value' not in attr:
raise ValueError("Invalid attribute structure")
return TrueИзбор на правилната IPFS Pinning услуга#
При избора на IPFS pinning услуга за вашия NFT проект, обмислете:
- Надеждност: Гарантирано време на работа за дългосрочно съхранение
- Производителност: Бързи скорости на извличане по целия свят
- Цени: Икономически ефективно за размера на вашата колекция
- Функции: API възможности, анализи и инструменти за разработчици
За подробно сравнение на pinning услуги прочетете нашето сравнение IPFS Ninja vs Pinata и нашето ръководство за най-добрите IPFS pinning услуги.
Разширени функции: Персонализирани шлюзове и анализи#
IPFS Ninja предлага допълнителни функции за професионални NFT проекти:
Конфигурация на персонализиран шлюз#
Създайте брандирани IPFS шлюзове за вашата колекция:
// Access your NFT through a custom gateway
const customGateway = 'https://my-collection.gw.ipfs.ninja';
const nftUrl = `${customGateway}/ipfs/${metadataCid}`;Анализи на качванията#
Наблюдавайте използването на NFT съхранението и моделите на достъп чрез анализите на таблото, помагайки ви да разберете производителността на колекцията и да оптимизирате разходите за съхранение.
Отстраняване на често срещани проблеми#
Метаданните не се зареждат#
- Уверете се, че IPFS URL адресите използват протокола
ipfs:// - Проверете дали JSON метаданните са валидни
- Уверете се, че pinning услугата поддържа съдържанието
Изображенията не се показват#
- Потвърдете, че CID-овете на изображенията са правилни в метаданните
- Тествайте URL адресите на изображенията в IPFS шлюзовете
- Уверете се, че форматите на файловете с изображения са съвместими с уеб
Грешки в оценката на gas#
- Уверете се, че функцията
tokenURIвръща валидни низове - Проверете за циклични препратки в метаданните
- Валидирайте всички IPFS CID-ове преди mint-ване
Мониторинг и поддръжка на вашето NFT съхранение#
След разполагане на вашата колекция:
- Редовни проверки на състоянието: Уверете се, че метаданните и изображенията остават достъпни
- Архивирайте важни CID-ове: Поддържайте записи на всички качени идентификатори на съдържание
- Наблюдавайте анализите: Проследявайте моделите на достъп и използването на съхранението
- Планирайте за мащабиране: Обмислете надграждане на вашата pinning услуга, тъй като колекцията ви расте
За повече подробности относно програмното управление на качванията, вижте нашия урок за IPFS upload API.
Заключение#
Съхранението на NFT метаданни в IPFS гарантира, че вашите цифрови активи остават дългосрочно достъпни и ценни. Следвайки това ръководство, научихте как да:
- Структурирате метаданни, съвместими с ERC-721
- Качвате активи и метаданни, използвайки Python и JavaScript
- Имплементирате правилни функции
tokenURI - Обработвате пакетни операции за големи колекции
- Прилагате най-добри практики за продукционни разполагания
Комбинацията от децентрализираната архитектура на IPFS и надеждните pinning услуги създава основата за успешни NFT проекти, които издържат теста на времето.
Готови ли сте да започнете с pinning? Създайте безплатен акаунт — 50 файла, 1 GB съхранение, 2 GB ширина на честотната лента/месец. Не се изисква кредитна карта.
За тази статия
Тази статия беше създадена с помощта на AI, прегледана от човек и проверена спрямо реалната платформа IPFS.NINJA преди публикуване. Научете как използваме AI в съдържанието си .

За автора
Nacho Coll
Founder & Engineer at IPFS.NINJA
Nacho founded IPFS.NINJA to make content-addressed storage feel as simple as an S3 PUT — a single API call, a permanent CID, no wallets or peer discovery to reason about. Writes about IPFS internals, decentralized storage patterns, and the pinning-service landscape from the operator side of the wire.
