Skip to content

Tương thích S3

Sử dụng AWS SDK để tải lên, tải xuống và quản lý tệp trên IPFS Ninja với cùng đoạn mã bạn dùng cho Amazon S3.

Endpoint

https://s3.ipfs.ninja

Thông tin xác thực

API S3 sử dụng khóa API IPFS Ninja của bạn để xác thực. Khóa API của bạn đóng vai trò cả access key và secret key.

Cách lấy thông tin xác thực

  1. Vào Bảng điều khiển > Khóa API
  2. Nhấp Tạo khóa API và đặt tên cho nó (ví dụ: "Truy cập S3")
  3. Sao chép ngay toàn bộ khóa — nó chỉ hiển thị một lần và không thể lấy lại sau đó

Khóa của bạn trông như thế này:

bws_628bba35e9e0079d9ff9c392b1b55a7b
├──────────┘└──────────────────────────┘
 tiền tố (12 ký tự)    phần còn lại của khóa

Ánh xạ sang thông tin xác thực AWS

Tham số AWSGiá trịVí dụ
accessKeyId12 ký tự đầu tiên của khóa APIbws_628bba35
secretAccessKeyToàn bộ khóa API (đầy đủ 36 ký tự)bws_628bba35e9e0079d9ff9c392b1b55a7b
regionLuôn là us-east-1us-east-1

WARNING

Toàn bộ khóa API chỉ hiển thị một lần khi bạn tạo nó. Nếu bạn làm mất nó, hãy xóa khóa và tạo khóa mới từ trang Khóa API.

Bắt đầu nhanh

javascript
import { S3Client, PutObjectCommand, GetObjectCommand } from "@aws-sdk/client-s3";

const s3 = new S3Client({
  endpoint: "https://s3.ipfs.ninja",
  credentials: {
    accessKeyId: "bws_628bba35",
    secretAccessKey: "bws_628bba35e9e0079d9ff9c392b1b55a7b"
  },
  region: "us-east-1",
  forcePathStyle: true
});

// Upload a file
const put = await s3.send(new PutObjectCommand({
  Bucket: "my-project",
  Key: "hello.json",
  Body: JSON.stringify({ hello: "IPFS" }),
  ContentType: "application/json"
}));

console.log("CID:", put.Metadata?.cid);
// CID: bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi

Bucket = Thư mục

Bucket S3 ánh xạ đến các thư mục IPFS Ninja của bạn. Khi bạn tải một tệp lên bucket, nó được lưu trong thư mục tương ứng. Khi bạn liệt kê các đối tượng trong một bucket, bạn thấy các tệp trong thư mục đó.

Thao tác S3Tương đương IPFS Ninja
CreateBucketTạo thư mục mới
ListBucketsLiệt kê thư mục của bạn
DeleteBucketXóa một thư mục và toàn bộ tệp bên trong
PutObject vào bucketTải tệp vào thư mục
ListObjectsV2 trên bucketLiệt kê tệp trong thư mục
javascript
import { ListBucketsCommand, CreateBucketCommand, PutObjectCommand } from "@aws-sdk/client-s3";

// Create a bucket (= create a folder)
await s3.send(new CreateBucketCommand({ Bucket: "nft-metadata" }));

// Upload a file into the folder
await s3.send(new PutObjectCommand({
  Bucket: "nft-metadata",      // ← folder name
  Key: "token-42.json",        // ← filename within the folder
  Body: JSON.stringify({ name: "My NFT #42" })
}));

// List buckets (= list your folders)
const { Buckets } = await s3.send(new ListBucketsCommand({}));
console.log(Buckets);
// [{ Name: "nft-metadata", CreationDate: "2026-04-13T..." }]

TIP

Các thư mục được tạo qua API S3 chính là các thư mục hiển thị trong Bảng điều khiển của bạn. Bạn có thể tổ chức tệp từ API S3, API REST hoặc giao diện web — tất cả đều dùng chung một hệ thống thư mục.

INFO

Không giống Amazon S3, các thư mục IPFS Ninja mặc định là phẳng. Để tạo cấu trúc lồng nhau, hãy dùng các endpoint thư mục của API REST với parentFolderId. Từ API S3, hãy dùng tiền tố key (ví dụ: images/photo.png) để tổ chức bên trong một thư mục.

Tên bucket là duy nhất trên toàn cục

Tên bucket tồn tại trong một không gian tên toàn cục trên tất cả khách hàng, khớp với ngữ nghĩa của AWS S3. Điều đó có nghĩa là:

  • Người dùng đầu tiên tạo bucket với một tên nhất định sẽ giữ tên đó trên toàn cục.
  • Các lệnh gọi CreateBucket sau đó với cùng tên từ bất kỳ tài khoản nào sẽ trả về BucketAlreadyExists (409).
  • Nếu bạn cố tạo lại bucket của chính mình, bạn sẽ nhận BucketAlreadyOwnedByYou (409).
  • Tên thư mục của bạn trên bảng điều khiển là theo từng tài khoản và vẫn có thể là bất kỳ tên nào — chỉ tên bucket hiển thị qua S3 mới đi qua không gian tên toàn cục.

Nếu tên bạn muốn đã bị chiếm, hãy chọn một tên có phạm vi khác (myapp-photos-2026, acme-nft-metadata) — cùng quy ước bạn sẽ dùng trên Amazon S3.

Các thao tác được hỗ trợ

PutObject

Tải một tệp lên IPFS. Tệp được ghim, quét an toàn, và CID được trả về trong tiêu đề ETagx-amz-meta-cid.

Để nhập một tệp CAR thay vì một tệp thông thường, hãy thêm tiêu đề siêu dữ liệu x-amz-meta-import: car. Xem Nhập CAR để biết chi tiết.

javascript
import { PutObjectCommand } from "@aws-sdk/client-s3";
import fs from "fs";

const result = await s3.send(new PutObjectCommand({
  Bucket: "my-project",
  Key: "photo.png",
  Body: fs.readFileSync("photo.png"),
  ContentType: "image/png"
}));

console.log("CID:", result.ETag);
bash
# tương đương curl
curl -X PUT "https://s3.ipfs.ninja/my-project/photo.png" \
  --data-binary @photo.png \
  -H "Content-Type: image/png" \
  --aws-sigv4 "aws:amz:us-east-1:s3" \
  --user "bws_628bba35:bws_628bba35e9e0079d9ff9c392b1b55a7b"

GetObject

Tải xuống một tệp theo key (tên tệp) hoặc CID của nó.

javascript
import { GetObjectCommand } from "@aws-sdk/client-s3";

const result = await s3.send(new GetObjectCommand({
  Bucket: "my-project",
  Key: "photo.png"
}));

const body = await result.Body.transformToByteArray();
console.log("Size:", body.length);
console.log("CID:", result.Metadata?.cid);

HeadObject

Lấy siêu dữ liệu tệp mà không cần tải nội dung xuống.

javascript
import { HeadObjectCommand } from "@aws-sdk/client-s3";

const head = await s3.send(new HeadObjectCommand({
  Bucket: "my-project",
  Key: "photo.png"
}));

console.log("Size:", head.ContentLength);
console.log("Type:", head.ContentType);
console.log("CID:", head.Metadata?.cid);

DeleteObject

Bỏ ghim một tệp khỏi IPFS và xóa nó khỏi tài khoản của bạn.

javascript
import { DeleteObjectCommand } from "@aws-sdk/client-s3";

await s3.send(new DeleteObjectCommand({
  Bucket: "my-project",
  Key: "photo.png"
}));

ListObjectsV2

Liệt kê tệp trong một bucket với bộ lọc tiền tố tùy chọn và phân trang.

javascript
import { ListObjectsV2Command } from "@aws-sdk/client-s3";

const list = await s3.send(new ListObjectsV2Command({
  Bucket: "my-project",
  Prefix: "images/",
  MaxKeys: 100
}));

for (const obj of list.Contents ?? []) {
  console.log(obj.Key, obj.Size, obj.ETag); // ETag = CID
}

Tải lên nhiều phần (Multipart)

Tải lên các tệp lớn (tối đa 5 GB) bằng tải lên nhiều phần. AWS SDK xử lý việc này tự động:

javascript
import { Upload } from "@aws-sdk/lib-storage";
import fs from "fs";

const upload = new Upload({
  client: s3,
  params: {
    Bucket: "my-project",
    Key: "large-dataset.tar.gz",
    Body: fs.createReadStream("large-dataset.tar.gz"),
    ContentType: "application/gzip"
  },
  partSize: 10 * 1024 * 1024, // 10 MB mỗi phần
});

upload.on("httpUploadProgress", (progress) => {
  console.log(`Uploaded ${progress.loaded} of ${progress.total} bytes`);
});

const result = await upload.done();
console.log("CID:", result.ETag);

Hoặc tự điều khiển các phần theo cách thủ công:

javascript
import {
  CreateMultipartUploadCommand,
  UploadPartCommand,
  CompleteMultipartUploadCommand
} from "@aws-sdk/client-s3";

// 1. Bắt đầu
const { UploadId } = await s3.send(new CreateMultipartUploadCommand({
  Bucket: "my-project",
  Key: "big-file.bin"
}));

// 2. Tải lên các phần
const part1 = await s3.send(new UploadPartCommand({
  Bucket: "my-project",
  Key: "big-file.bin",
  UploadId,
  PartNumber: 1,
  Body: chunk1
}));

// 3. Hoàn tất
const result = await s3.send(new CompleteMultipartUploadCommand({
  Bucket: "my-project",
  Key: "big-file.bin",
  UploadId,
  MultipartUpload: {
    Parts: [{ PartNumber: 1, ETag: part1.ETag }]
  }
}));

Ví dụ Python

python
import boto3

s3 = boto3.client(
    "s3",
    endpoint_url="https://s3.ipfs.ninja",
    aws_access_key_id="bws_628bba35",
    aws_secret_access_key="bws_628bba35e9e0079d9ff9c392b1b55a7b",
    region_name="us-east-1"
)

# Upload
s3.put_object(
    Bucket="my-project",
    Key="data.json",
    Body=b'{"hello": "IPFS"}',
    ContentType="application/json"
)

# List files
response = s3.list_objects_v2(Bucket="my-project")
for obj in response.get("Contents", []):
    print(obj["Key"], obj["Size"])

# Download
result = s3.get_object(Bucket="my-project", Key="data.json")
print(result["Body"].read())

Ví dụ Go

go
package main

import (
    "context"
    "fmt"
    "strings"

    "github.com/aws/aws-sdk-go-v2/aws"
    "github.com/aws/aws-sdk-go-v2/credentials"
    "github.com/aws/aws-sdk-go-v2/service/s3"
)

func main() {
    client := s3.New(s3.Options{
        BaseEndpoint: aws.String("https://s3.ipfs.ninja"),
        Region:       "us-east-1",
        Credentials:  credentials.NewStaticCredentialsProvider("bws_628bba35", "bws_628bba35e9e0...", ""),
        UsePathStyle: true,
    })

    _, err := client.PutObject(context.TODO(), &s3.PutObjectInput{
        Bucket:      aws.String("my-project"),
        Key:         aws.String("hello.txt"),
        Body:        strings.NewReader("Hello, IPFS!"),
        ContentType: aws.String("text/plain"),
    })
    if err != nil {
        panic(err)
    }
    fmt.Println("Uploaded!")
}

Cấu hình CORS (truy cập SDK trình duyệt)

Nếu bạn gọi API S3 trực tiếp từ JavaScript trình duyệt (SPA, ứng dụng ví, công cụ bảng điều khiển), bạn cần cấu hình CORS trên bucket trước. Nếu không, trình duyệt sẽ chặn preflight và các lần tải lên của bạn sẽ thất bại với thông báo No 'Access-Control-Allow-Origin' header is present.

Cùng hình dạng như AWS S3 — các subresource PutBucketCors / GetBucketCors / DeleteBucketCors:

PutBucketCors

javascript
import { S3Client, PutBucketCorsCommand } from "@aws-sdk/client-s3";

await s3.send(new PutBucketCorsCommand({
  Bucket: "my-bucket",
  CORSConfiguration: {
    CORSRules: [{
      AllowedOrigins: ["http://localhost:3000", "https://myapp.com"],
      AllowedMethods: ["GET", "HEAD", "PUT", "POST", "DELETE"],
      AllowedHeaders: ["*"],
      ExposeHeaders: ["ETag", "x-amz-meta-cid", "x-amz-request-id"],
      MaxAgeSeconds: 3600,
    }],
  },
}));

GetBucketCors

javascript
import { GetBucketCorsCommand } from "@aws-sdk/client-s3";

const { CORSRules } = await s3.send(new GetBucketCorsCommand({ Bucket: "my-bucket" }));
console.log(CORSRules);

DeleteBucketCors

javascript
import { DeleteBucketCorsCommand } from "@aws-sdk/client-s3";

await s3.send(new DeleteBucketCorsCommand({ Bucket: "my-bucket" }));

Giới hạn và giá trị mặc định

  • Tối đa 5 quy tắc mỗi bucket (đặc tả cho phép 100; chúng tôi giới hạn ở 5 để giữ phản hồi preflight của trình duyệt gọn nhẹ).
  • Tổng cấu hình giới hạn ở 64 KB khi tuần tự hóa.
  • Nếu không có cấu hình CORS nào được đặt, preflight của trình duyệt sẽ bị từ chối — khớp với hành vi mặc định của AWS S3. Hãy cấu hình quy tắc rõ ràng cho các nguồn gốc bạn thực sự phục vụ.

Lưu ý bảo mật thực tế

CORS là một lớp tiện lợi phía trình duyệt, không phải là một ranh giới bảo mật. Mọi lệnh gọi API S3 vẫn yêu cầu chữ ký SigV4 hợp lệ được tính từ khóa API của bạn — một cấu hình CORS cho phép nhiều nguồn gốc không cho phép bất kỳ ai sử dụng bucket của bạn mà không có thông tin xác thực đó. Điều CORS thực sự ngăn chặn: một nguồn gốc không mong muốn (ví dụ: một bản sao cũ của ứng dụng bạn trên dev.myapp.com) gửi các yêu cầu đã ký từ ngữ cảnh trình duyệt.

Lựa chọn thay thế trên bảng điều khiển

Trang Tệp có mục S3 CORS trong menu hành động của mỗi thư mục. Cùng kho lưu trữ bên dưới; nếu bạn không muốn viết mã PutBucketCors, hãy cấu hình ở đó.

Khác biệt so với Amazon S3

Tính năngAmazon S3IPFS Ninja S3
Mô hình lưu trữĐối tượng có thể thay đổiĐịnh địa chỉ theo nội dung (CID bất biến)
Hành vi ghi đèThay thế đối tượng tại chỗTạo CID mới, CID cũ vẫn có thể truy cập
Kiểm soát phiên bảnĐược hỗ trợKhông hỗ trợ (dùng CID để quản lý phiên bản)
Mã hóa phía máy chủĐược hỗ trợKhông hỗ trợ (nội dung nằm trên IPFS)
Chính sách vòng đờiĐược hỗ trợKhông hỗ trợ
Chính sách bucket / ACLĐược hỗ trợDùng chế độ truy cập gateway
URL có chữ ký trướcĐược hỗ trợDùng token tải lên có chữ ký
Kích thước đối tượng tối đa5 TB5 GB (nhiều phần), 100 MB (PUT đơn)
Khu vựcĐa khu vựcChỉ us-east-1
Giá trị ETagHàm băm MD5CID IPFS
Tiêu đề bổ sungS3 chuẩnx-amz-meta-cid (CID IPFS)
Định dạng CIDKhông áp dụngCIDv1 hiện đại (bafy…) cho tải lên mới; Qm… cũ vẫn hợp lệ làm đầu vào
Không gian tên bucketToàn cục (toàn AWS)Toàn cục (trên tất cả tài khoản IPFS Ninja) — cùng ngữ nghĩa
CORSHỗ trợ PutBucketCorsHỗ trợ PutBucketCors (giới hạn 5 quy tắc)

Di chuyển từ Amazon S3

Thay thế cấu hình client S3 của bạn:

diff
 const s3 = new S3Client({
+  endpoint: "https://s3.ipfs.ninja",
   credentials: {
-    accessKeyId: "AKIA...",
-    secretAccessKey: "wJalrX..."
+    accessKeyId: "bws_628bba35",
+    secretAccessKey: "bws_628bba35e9e0..."
   },
   region: "us-east-1",
+  forcePathStyle: true
 });

Các lệnh gọi PutObject, GetObject, ListObjectsV2DeleteObject hiện có của bạn hoạt động không thay đổi.

Di chuyển từ Filebase

Thay thế URL endpoint:

diff
 const s3 = new S3Client({
-  endpoint: "https://s3.filebase.com",
+  endpoint: "https://s3.ipfs.ninja",
   credentials: {
-    accessKeyId: "FILEBASE_KEY",
-    secretAccessKey: "FILEBASE_SECRET"
+    accessKeyId: "bws_628bba35",
+    secretAccessKey: "bws_628bba35e9e0..."
   },
   region: "us-east-1",
   forcePathStyle: true
 });