全部產品
Search
文件中心

Object Storage Service:使用AWS SDK訪問OSS

更新時間:Feb 03, 2026

OSS 相容 AWS S3 API,使用 AWS SDK 訪問 OSS 時,無需改動代碼,只需配置 OSS 的 Endpoint訪問憑證

  • Endpoint:使用S3相容格式的外網Endpoint(https://s3.oss-{region}.aliyuncs.com)或內網Endpoint(https://s3.oss-{region}-internal.aliyuncs.com)。將{region}替換為實際地區ID,如cn-hangzhou。完整地區列表見地區和Endpoint

    重要

    根據策略調整,為提升OSS服務的合規性和安全性,自2025年3月20日起,新開通OSS服務的使用者在中國內地地區的Bucket將無法通過預設外網網域名稱調用資料操作類API(如上傳、下載檔案),需通過自訂網域名(CNAME)方式訪問OSS服務。使用HTTPS協議訪問(如控制台)時,還需為自訂網域名配置SSL認證

  • 訪問憑證:RAM 存取控制建立有 OSS 存取權限的 AccessKey。

Java

SDK 2.x

import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.S3Configuration;
import java.net.URI;

S3Client s3Client = S3Client.builder()
    .endpointOverride(URI.create("https://s3.oss-cn-hangzhou.aliyuncs.com"))
    .region(Region.AWS_GLOBAL)
    .serviceConfiguration(
        S3Configuration.builder()
            .pathStyleAccessEnabled(false)
            .chunkedEncodingEnabled(false)
            .build()
    )
    .build();

SDK 1.x

import com.amazonaws.client.builder.AwsClientBuilder.EndpointConfiguration;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;

AmazonS3 s3Client = AmazonS3ClientBuilder.standard()
    .withEndpointConfiguration(new EndpointConfiguration(
        "https://s3.oss-cn-hangzhou.aliyuncs.com", 
        "cn-hangzhou"))
    .withPathStyleAccessEnabled(false)
    .withChunkedEncodingDisabled(false)
    .build();

SDK 1.x 的 getObject 返回的 S3ObjectInputStream 調用 close() 會立即丟棄未讀資料,應先完整讀取。

S3Object object = s3Client.getObject("my-bucket", "file.txt");
InputStream input = object.getObjectContent();

byte[ ] data = IOUtils.toByteArray(input);

input.close();

Python

import boto3
from botocore.config import Config

s3 = boto3.client(
    's3',
    endpoint_url='https://s3.oss-cn-hangzhou.aliyuncs.com',
    config=Config(
        signature_version='s3',
        s3={'addressing_style': 'virtual'}
    )
)

Node.js

SDK v3

import { S3Client } from '@aws-sdk/client-s3';

const client = new S3Client({
    endpoint: 'https://s3.oss-cn-hangzhou.aliyuncs.com',
    region: 'cn-hangzhou'
});

SDK v2

const AWS = require('aws-sdk');

const s3 = new AWS.S3({
    endpoint: 'https://s3.oss-cn-hangzhou.aliyuncs.com',
    region: 'cn-hangzhou'
});

Go

SDK v2

import (
    "context"
    "github.com/aws/aws-sdk-go-v2/aws"
    awsconfig "github.com/aws/aws-sdk-go-v2/config"
    "github.com/aws/aws-sdk-go-v2/service/s3"
)

cfg, _ := awsconfig.LoadDefaultConfig(context.TODO(),
    awsconfig.WithEndpointResolverWithOptions(
        aws.EndpointResolverWithOptionsFunc(func(service, region string, options ...interface{}) (aws.Endpoint, error) {
            return aws.Endpoint{
                URL: "https://s3.oss-cn-hangzhou.aliyuncs.com",
            }, nil
        }),
    ),
)
client := s3.NewFromConfig(cfg)

SDK v1

import (
    "github.com/aws/aws-sdk-go/aws"
    "github.com/aws/aws-sdk-go/aws/session"
    "github.com/aws/aws-sdk-go/service/s3"
)

sess := session.Must(session.NewSessionWithOptions(session.Options{
    Config: aws.Config{
        Endpoint: aws.String("https://s3.oss-cn-hangzhou.aliyuncs.com"),
        Region:   aws.String("cn-hangzhou"),
    },
    SharedConfigState: session.SharedConfigEnable,
}))
svc := s3.New(sess)

.NET

SDK 3.x

using Amazon.S3;

var config = new AmazonS3Config
{
    ServiceURL = "https://s3.oss-cn-hangzhou.aliyuncs.com"
};
var client = new AmazonS3Client(config);

SDK 2.x

using Amazon.S3;

var config = new AmazonS3Config
{
    ServiceURL = "https://s3.oss-cn-hangzhou.aliyuncs.com"
};
var client = new AmazonS3Client(config);

PHP

SDK 3.x

<?php
require_once __DIR__ . '/vendor/autoload.php';
use Aws\S3\S3Client;

$s3Client = new S3Client([
    'version' => '2006-03-01',
    'region'  => 'cn-hangzhou',
    'endpoint' => 'https://s3.oss-cn-hangzhou.aliyuncs.com'
]);

SDK 2.x

<?php
require_once __DIR__ . '/vendor/autoload.php';
use Aws\S3\S3Client;

$s3Client = S3Client::factory([
    'version' => '2006-03-01',
    'region'  => 'cn-hangzhou',
    'base_url' => 'https://s3.oss-cn-hangzhou.aliyuncs.com'
]);

Ruby

SDK 3.x

require 'aws-sdk-s3'

s3 = Aws::S3::Client.new(
  endpoint: 'https://s3.oss-cn-hangzhou.aliyuncs.com',
  region: 'cn-hangzhou'
)

SDK 2.x

require 'aws-sdk'

s3 = AWS::S3::Client.new(
  s3_endpoint: 's3.oss-cn-hangzhou.aliyuncs.com',
  region: 'cn-hangzhou',
  s3_force_path_style: false
)

C++

要求SDK 1.7.68及以上版本。

#include <aws/s3/S3Client.h>
#include <aws/core/client/ClientConfiguration.h>

Aws::Client::ClientConfiguration config;
config.endpointOverride = "s3.oss-cn-hangzhou.aliyuncs.com";
config.region = "cn-hangzhou";

Aws::S3::S3Client s3_client(config);

Browser

Web前端應用使用STS臨時憑證,禁止在用戶端寫入程式碼永久AccessKey。服務端調用AssumeRole擷取臨時憑證並返回給用戶端。完整教程見使用STS臨時訪問憑證訪問OSS

import { S3Client } from '@aws-sdk/client-s3';

// 從服務端擷取STS臨時憑證
async function getSTSCredentials() {
    const response = await fetch('https://your-server.com/api/sts-token');
    return await response.json();
}

// 使用臨時憑證初始化S3用戶端
const client = new S3Client({
    region: 'cn-hangzhou',
    endpoint: 'https://s3.oss-cn-hangzhou.aliyuncs.com',
    credentials: async () => {
        const creds = await getSTSCredentials();
        return {
            accessKeyId: creds.accessKeyId,
            secretAccessKey: creds.secretAccessKey,
            sessionToken: creds.securityToken,
            expiration: new Date(creds.expiration)
        };
    }
});

Android

行動裝置 App(Android)使用STS臨時憑證,禁止在用戶端寫入程式碼永久AccessKey。服務端調用AssumeRole擷取臨時憑證並返回給用戶端。完整教程見使用STS臨時訪問憑證訪問OSS

import com.amazonaws.auth.AWSCredentialsProvider;
import com.amazonaws.auth.BasicSessionCredentials;
import com.amazonaws.client.builder.AwsClientBuilder.EndpointConfiguration;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3Client;

// 實現憑證提供器,從服務端擷取STS臨時憑證
public class OSSCredentialsProvider implements AWSCredentialsProvider {
    @Override
    public AWSCredentials getCredentials() {
        // 從您的服務端擷取STS臨時憑證
        // 請求 https://your-server.com/api/sts-token
        String accessKeyId = fetchFromServer("accessKeyId");
        String secretKeyId = fetchFromServer("secretKeyId");
        String securityToken = fetchFromServer("securityToken");
        
        return new BasicSessionCredentials(accessKeyId, secretKeyId, securityToken);
    }
    
    @Override
    public void refresh() {
        // 重新整理憑證
    }
}

// 建立S3用戶端
AmazonS3 s3Client = AmazonS3Client.builder()
    .withCredentials(new OSSCredentialsProvider())
    .withEndpointConfiguration(new EndpointConfiguration(
        "https://s3.oss-cn-hangzhou.aliyuncs.com", ""))
    .build();

// 業務代碼
s3Client.putObject("my-bucket", "test.txt", "Hello OSS");

iOS

行動裝置 App(iOS)使用STS臨時憑證,禁止在用戶端寫入程式碼永久AccessKey。服務端調用AssumeRole擷取臨時憑證並返回給用戶端。完整教程見使用STS臨時訪問憑證訪問OSS

#import <AWSS3/AWSS3.h>

// 實現憑證提供器
@interface OSSCredentialsProvider : NSObject <AWSCredentialsProvider>
@end

@implementation OSSCredentialsProvider

- (AWSTask<AWSCredentials *> *)credentials {
    return [[AWSTask taskWithResult:nil] continueWithBlock:^id(AWSTask *task) {
        // 從服務端擷取STS臨時憑證
        NSString *accessKey = [self fetchFromServer:@"accessKeyId"];
        NSString *secretKey = [self fetchFromServer:@"secretKeyId"];
        NSString *sessionToken = [self fetchFromServer:@"securityToken"];
        
        AWSCredentials *credentials = [[AWSCredentials alloc]
            initWithAccessKey:accessKey
            secretKey:secretKey
            sessionKey:sessionToken
            expiration:[NSDate dateWithTimeIntervalSinceNow:3600]];
        
        return [AWSTask taskWithResult:credentials];
    }];
}

@end

// 配置S3用戶端
AWSEndpoint *endpoint = [[AWSEndpoint alloc] initWithURLString:@"https://s3.oss-cn-hangzhou.aliyuncs.com"];
AWSServiceConfiguration *configuration = [[AWSServiceConfiguration alloc]
    initWithRegion:AWSRegionUnknown
    endpoint:endpoint
    credentialsProvider:[[OSSCredentialsProvider alloc] init]];

[AWSS3 registerS3WithConfiguration:configuration forKey:@"OSS"];
AWSS3 *s3 = [AWSS3 S3ForKey:@"OSS"];

// 業務代碼
AWSS3PutObjectRequest *request = [AWSS3PutObjectRequest new];
request.bucket = @"my-bucket";
request.key = @"test.txt";
request.body = [@"Hello OSS" dataUsingEncoding:NSUTF8StringEncoding];

[[s3 putObject:request] continueWithBlock:^id(AWSTask *task) {
    if (task.error) {
        NSLog(@"Error: %@", task.error);
    } else {
        NSLog(@"Success");
    }
    return nil;
}];

常見問題

上傳失敗:InvalidArgument: aws-chunked encoding is not supported

癥狀:上傳檔案時報錯:

InvalidArgument: aws-chunked encoding is not supported with the specified x-amz-content-sha256 value

根本原因

這是使用AWS SDK訪問OSS最常見的問題。OSS支援AWS Signature V4簽名演算法,但在傳輸編碼上有差異:

  • AWS S3:預設使用chunked encoding傳輸大檔案

  • OSS:不支援chunked encoding傳輸

原因分析

部分SDK的V4簽名實現綁定了chunked encoding:

  • Python (boto3):V4簽名強制使用chunked encoding,無法禁用 → 改用V2簽名

  • Java:可以通過配置禁用chunked encoding

  • Go/Node.js:預設不使用chunked encoding,無需特殊處理

解決方案(按SDK分類)

SDK

解決方案

原因

Python (boto3)

使用V2簽名:signature_version='s3'

boto3的V4實現綁定chunked encoding,無法禁用

Java 1.x

V4簽名 + .withChunkedEncodingDisabled(true)

可以禁用chunked encoding

Java 2.x

V4簽名 + .chunkedEncodingEnabled(false)

可以禁用chunked encoding

Go v1

V4簽名

預設不使用chunked encoding

Go v2

V4簽名;Manager上傳大檔案需注意

Manager功能可能使用chunked encoding

Node.js v3

V4簽名

預設不使用chunked encoding

Python樣本(修複前後)

# 錯誤配置(boto3的V4實現使用chunked encoding)
s3 = boto3.client('s3',
    endpoint_url='https://oss-cn-hongkong.aliyuncs.com',
    config=Config(signature_version='v4'))

# 正確配置(boto3使用V2簽名)
s3 = boto3.client('s3',
    endpoint_url='https://oss-cn-hongkong.aliyuncs.com',
    config=Config(signature_version='s3'))  # V2簽名是boto3的穩定方案

技術說明

OSS的V4簽名遵循AWS Signature Version 4規範,但要求:

  • 要求標頭包含:x-oss-content-sha256: UNSIGNED-PAYLOAD

  • 不使用Transfer-Encoding: chunked傳輸方式

大部分SDK可以通過配置實現相容,但boto3的V4簽名實現與chunked encoding強耦合,因此boto3需使用V2簽名。

SDK版本和簽名版本選擇

版本選擇參考

語言

SDK版本

簽名版本

配置要點

Python

boto3最新版

V2簽名(s3

boto3的V4實現與OSS不相容

Java 1.x

最新1.x

V4簽名

需禁用chunked encoding

Java 2.x

最新2.x

V4簽名

需禁用chunked encoding

Node.js

v3

V4簽名(預設)

-

Go v1

最新v1

V4簽名(預設)

-

Go v2

最新v2

V4簽名(預設)

Manager上傳大檔案需注意

簽名版本說明

  • OSS V4簽名:OSS完整支援AWS Signature V4演算法

  • V2簽名:boto3特殊情況,因SDK實現限制需使用V2

  • 相容性:除boto3外,其他SDK均可使用V4簽名訪問OSS

新專案版本選擇參考

情境

可選方案

原因

Python新專案

boto3 + V2簽名

boto3暫不支援OSS V4

Java新專案

Java 2.x + V4簽名

效能更好

Node.js新專案

v3 + V4簽名

-

Go新專案

Go v1 + V4簽名

推薦

已有專案遷移

保持當前SDK版本

最小化改動風險

簽名錯誤:SignatureDoesNotMatch

可能遇到SignatureDoesNotMatch錯誤,提示服務端計算的簽名與用戶端提供的簽名不匹配。

最常見的原因是代碼中仍在使用AWS的AccessKey而不是OSS的AccessKey。AWS的訪問憑證和OSS的訪問憑證是完全獨立的兩套系統,不能混用。檢查代碼中的aws_access_key_idaws_secret_access_key等參數,確保使用的是OSS控制台中建立的AccessKey ID和AccessKey Secret。

第二個常見原因是伺服器時鐘偏差。S3簽名演算法會在簽名中包含時間戳記,OSS服務端會驗證請求時間與伺服器時間的差異。如果你的伺服器時間與標準時間相差超過15分鐘,所有請求都會被拒絕。可以通過date -u命令檢查伺服器的UTC時間,如果時間不準確,使用ntpdate或系統時間同步服務校正時間。

第三個原因是endpoint配置錯誤。如果endpoint仍然指向AWS網域名稱(如s3.amazonaws.com),或者使用了錯誤的OSS region,簽名計算會失敗。OSS endpoint的標準格式是https://oss-{region}.aliyuncs.com,其中region與bucket所在的OSS地區一致,比如oss-cn-hangzhouoss-cn-beijing等。

使用boto3時,還有一個特殊原因:如果未配置signature_version='s3',boto3會使用預設的V4簽名,這會導致簽名失敗。正確的boto3配置包含Config(signature_version='s3')參數。

驗證配置是否正確的一個簡單方法是使用ossutil命令列工具。運行ossutil ls oss://your-bucket --access-key-id <key> --access-key-secret <secret> --endpoint oss-cn-hangzhou.aliyuncs.com,如果能成功列出bucket內容,說明訪問憑證和endpoint配置是正確的,問題出在代碼配置上。

Bucket訪問錯誤

NoSuchBucketAccessDenied錯誤表示無法訪問指定的bucket。最常見的原因是endpoint與bucket所在region不匹配。

OSS的每個bucket都屬於特定的region,比如cn-hangzhoucn-beijing等。訪問bucket時,endpoint使用bucket所在region的網域名稱。如果您的bucket在杭州region,endpoint是oss-cn-hangzhou.aliyuncs.com,而不能使用北京region的oss-cn-beijing.aliyuncs.com。這與AWS S3不同,AWS S3允許跨region訪問,但會自動重新導向。OSS不支援跨region訪問,錯誤的endpoint會直接返回NoSuchBucket錯誤。

第二個原因是RAM許可權配置問題。檢查您的OSS AccessKey對應的RAM使用者是否有訪問目標bucket的許可權。在OSS控制台的Resource Access Management頁面,確認該帳號被授予了oss:ListObjectsoss:GetObjectoss:PutObject等必需的許可權。

第三個原因與bucket命名規範有關。OSS支援兩種URL樣式:虛擬機器主機樣式(bucket-name.oss-cn-hangzhou.aliyuncs.com)和路徑樣式(oss-cn-hangzhou.aliyuncs.com/bucket-name)。當使用虛擬機器主機樣式時,bucket名稱符合DNS命名規範,不能包含底線。如果您的bucket名稱包含底線,需要在SDK配置中使用路徑樣式,或者建立新的符合命名規範的bucket。

效能最佳化

大檔案上傳和下載是Object Storage Service應用中的常見需求。AWS SDK提供了多種傳輸加速機制,這些機制在OSS上同樣有效。

使用Python boto3時,可以通過TransferConfig配置分區上傳參數。當上傳檔案大於配置的閾值時,boto3會自動將檔案分成多個部分並發上傳,顯著提高傳輸速度。multipart_threshold參數控制啟用分區上傳的檔案大小閾值,max_concurrency控制並發上傳的線程數,multipart_chunksize控制每個分區的大小。合理配置這些參數可以讓100MB以上的大檔案上傳速度提升數倍。

使用Java SDK時,TransferManager類封裝了分區上傳、並發傳輸、自動重試等功能。TransferManager會根據檔案大小自動選擇最優的傳輸策略,無需手動處理分區邏輯。

使用Go SDK時,應該調用s3manager.Uploader而不是直接調用PutObjectUploader內建了並發分區上傳功能,可以自動將大檔案分割並發上傳,同時處理上傳失敗的重試邏輯。

使用Node.js SDK時,可以使用@aws-sdk/lib-storage包提供的Upload類。這個類支援流式上傳,可以在讀取檔案的同時開始上傳,減少記憶體佔用。前面Node.js章節已經展示了使用樣本。

所有這些傳輸加速機制都是基於S3的分區上傳API(Multipart Upload),OSS完全相容這些API,因此可以直接使用,無需修改代碼。