· Nacho Coll · Guides · 9 minit bacaan
Penyimpanan Metadata NFT: Panduan Lengkap IPFS untuk Pencipta NFT
Panduan langkah demi langkah untuk menyimpan metadata NFT pada IPFS. Termasuk corak ERC-721 tokenURI, contoh Python dan JavaScript.

Mencipta NFT memerlukan lebih daripada sekadar penggunaan kontrak pintar — anda memerlukan penyimpanan terdesentralisasi yang boleh dipercayai untuk metadata dan aset anda. Panduan komprehensif ini akan membawa anda langkah demi langkah melalui penyimpanan metadata NFT pada IPFS menggunakan amalan terbaik industri, lengkap dengan contoh kod untuk pembangun Python dan JavaScript.

Mengapa IPFS untuk Penyimpanan Metadata NFT?
Pengehosan web tradisional mewujudkan risiko pemusatan untuk projek NFT. Apabila metadata tinggal pada pelayan konvensional, NFT boleh menjadi “rosak” jika perkhidmatan pengehosan terganggu atau menukar URL. IPFS (InterPlanetary File System) menyelesaikan ini dengan menyediakan:
- Pengalamatan kandungan tidak boleh ubah: Setiap fail mendapat Content Identifier (CID) unik yang tidak pernah berubah
- Penyimpanan terdesentralisasi: Kandungan wujud di pelbagai nod di seluruh dunia
- Pengesahan kriptografi: Integriti fail dijamin melalui pencincangan kandungan
- URL kalis masa depan: Pautan IPFS berfungsi tanpa had, melindungi nilai jangka panjang
Untuk pemahaman yang lebih mendalam tentang asas IPFS, lihat panduan kami tentang apakah itu IPFS pinning.
Memahami Struktur Metadata ERC-721
Standard ERC-721 mendefinisikan cara metadata NFT harus distrukturkan. Fungsi tokenURI kontrak pintar anda mengembalikan URL yang menunjuk ke metadata JSON mengikut corak ini:
{
"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"
}Medan Metadata Utama
- name: Tajuk NFT yang dipaparkan dalam dompet dan pasaran
- description: Maklumat terperinci tentang NFT
- image: URL IPFS ke aset visual utama
- attributes: Sifat berdasarkan ciri untuk penapisan dan pengiraan keunikan
- external_url: Pautan pilihan ke kandungan tambahan atau laman web projek anda
Proses Penyimpanan NFT IPFS Langkah demi Langkah
Langkah 1: Sediakan Aset dan Metadata Anda
Sebelum memuat naik apa-apa, susun fail anda:
- Aset utama: Imej, video atau kandungan utama lain
- Fail metadata: Fail JSON yang menerangkan setiap NFT
- Metadata koleksi: Maklumat tahap koleksi pilihan
Langkah 2: Muat Naik Aset ke IPFS
Mulakan dengan memuat naik aset NFT utama anda (imej, video, dll.) untuk mendapatkan CID IPFS mereka. Anda akan merujuk kepada CID ini dalam fail JSON metadata anda.
Berikut adalah cara memuat naik imej menggunakan 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)Langkah 3: Cipta dan Muat Naik JSON Metadata
Setelah anda mempunyai CID aset, cipta fail JSON metadata dan muat naik:
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
)Langkah 4: Pelaksanaan JavaScript
Untuk aplikasi web atau projek Node.js, berikut adalah setara 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);
}
}Melaksanakan tokenURI dalam Kontrak Pintar Anda
Setelah metadata anda dimuat naik ke IPFS, laksanakan fungsi tokenURI dalam kontrak ERC-721 anda:
// 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;
}
}Operasi Berkelompok untuk Koleksi Besar
Untuk koleksi NFT yang besar, operasi berkelompok menjimatkan masa dan kos 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)Amalan Terbaik untuk Penyimpanan Metadata NFT
1. Gunakan Nama Fail Deskriptif
Apabila memuat naik ke IPFS, gunakan penerangan yang bermakna untuk membantu organisasi:
payload = {
"content": base64_content,
"description": f"Collection: {collection_name} | Token: {token_id} | Type: {file_type}"
}2. Laksanakan Pengendalian Ralat yang Betul
Sentiasa kendalikan kegagalan muat naik dengan elegan:
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. Sahkan Struktur Metadata
Pastikan metadata anda mematuhi standard:
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 TrueMemilih Perkhidmatan IPFS Pinning yang Tepat
Apabila memilih perkhidmatan IPFS pinning untuk projek NFT anda, pertimbangkan:
- Kebolehpercayaan: Masa operasi terjamin untuk penyimpanan jangka panjang
- Prestasi: Kelajuan pengambilan pantas di seluruh dunia
- Harga: Kos efektif untuk saiz koleksi anda
- Ciri-ciri: Keupayaan API, analitik dan alat pembangun
Untuk perbandingan terperinci perkhidmatan pinning, baca perbandingan kami IPFS Ninja vs Pinata dan panduan kami tentang perkhidmatan IPFS pinning terbaik.
Ciri-ciri Lanjutan: Get Tersuai dan Analitik
IPFS Ninja menawarkan ciri-ciri tambahan untuk projek NFT profesional:
Konfigurasi Get Tersuai
Cipta get IPFS berjenama untuk koleksi anda:
// Access your NFT through a custom gateway
const customGateway = 'https://my-collection.gw.ipfs.ninja';
const nftUrl = `${customGateway}/ipfs/${metadataCid}`;Analitik Muat Naik
Pantau penggunaan storan NFT dan corak akses melalui analitik papan pemuka, membantu anda memahami prestasi koleksi dan mengoptimumkan kos penyimpanan.
Menyelesaikan Masalah Biasa
Metadata Tidak Dimuatkan
- Sahkan URL IPFS menggunakan protokol
ipfs:// - Periksa metadata JSON adalah sah
- Pastikan perkhidmatan pinning sedang mengekalkan kandungan
Imej Tidak Dipaparkan
- Sahkan CID imej adalah betul dalam metadata
- Uji URL imej dalam get IPFS
- Sahkan format fail imej serasi dengan web
Ralat Anggaran Gas
- Pastikan fungsi
tokenURImengembalikan rentetan yang sah - Periksa rujukan kitaran dalam metadata
- Sahkan semua CID IPFS sebelum minting
Memantau dan Mengekalkan Storan NFT Anda
Selepas menggunakan koleksi anda:
- Pemeriksaan Kesihatan Berkala: Sahkan metadata dan imej kekal boleh diakses
- Sandar CID Penting: Simpan rekod semua pengecam kandungan yang dimuat naik
- Pantau Analitik: Jejaki corak akses dan penggunaan storan
- Rancang untuk Skala: Pertimbangkan menaik taraf perkhidmatan pinning anda apabila koleksi anda berkembang
Untuk butiran lanjut tentang menguruskan muat naik secara programatik, lihat tutorial API muat naik IPFS kami.
Kesimpulan
Menyimpan metadata NFT pada IPFS memastikan aset digital anda kekal boleh diakses dan bernilai dalam jangka panjang. Dengan mengikuti panduan ini, anda telah belajar:
- Menstrukturkan metadata yang mematuhi ERC-721
- Memuat naik aset dan metadata menggunakan Python dan JavaScript
- Melaksanakan fungsi
tokenURIyang sesuai - Mengendalikan operasi berkelompok untuk koleksi besar
- Menerapkan amalan terbaik untuk penggunaan pengeluaran
Kombinasi seni bina IPFS terdesentralisasi dan perkhidmatan pinning yang boleh dipercayai mewujudkan asas untuk projek NFT yang berjaya yang tahan ujian masa.
Bersedia untuk mulakan dengan pinning? Cipta akaun percuma — 50 fail, 1 GB storan, 2 GB lebar jalur/bulan. Tiada kad kredit diperlukan.
