快速接入
通過以下步驟快速接入 OSS Java SDK V1:
準備環境
安裝 Java 7 及以上版本。通過 java -version 命令查看 Java 版本,如當前環境沒有 Java 或版本低於 Java 7,請下載Java。
安裝 SDK
根據開發環境選擇合適的安裝方式。建議使用最新版本的 OSS Java SDK V1,確保程式碼範例正常運行。
以安裝3.17.4版本的OSS Java SDK V1為例進行介紹。
添加Maven依賴(推薦)
在Maven專案中使用OSS Java SDK V1,只需在pom.xml中加入相應依賴。
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.17.4</version>
</dependency>如使用Java 9及以上版本,需要添加以下JAXB相關依賴。
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
<!-- no more than 2.3.3-->
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.3.3</version>
</dependency>在Eclipse專案中匯入JAR包
下載OSS Java SDK V1。
解壓開發包。
將解壓後檔案夾中的檔案aliyun-sdk-oss-3.17.4.jar以及lib檔案夾下的所有檔案拷貝到專案中。
在Eclipse中選擇工程,右鍵選擇。
選中拷貝的所有JAR檔案,匯入到Libraries中。
在IntelliJ IDEA專案中匯入JAR包
下載OSS Java SDK V1 。
解壓開發包。
將解壓後檔案夾中的檔案aliyun-sdk-oss-3.17.4.jar以及lib檔案夾下的所有JAR檔案拷貝到專案中。
在IntelliJ IDEA中選擇工程,右鍵選擇 。
選中拷貝的所有JAR檔案,匯入到External Libraries中。
配置訪問憑證
使用 RAM 使用者的 AccessKey 配置訪問憑證。
在 RAM 控制台,建立使用永久 AccessKey 訪問的 RAM 使用者,儲存 AccessKey,然後為該使用者授予
AliyunOSSFullAccess許可權。使用 RAM 使用者的 AccessKey 配置環境變數。
Linux
在命令列介面執行以下命令,將環境變數設定追加到
~/.bashrc檔案中。echo "export OSS_ACCESS_KEY_ID='YOUR_ACCESS_KEY_ID'" >> ~/.bashrc echo "export OSS_ACCESS_KEY_SECRET='YOUR_ACCESS_KEY_SECRET'" >> ~/.bashrc執行以下命令使變更生效。
source ~/.bashrc執行以下命令檢查環境變數是否生效。
echo $OSS_ACCESS_KEY_ID echo $OSS_ACCESS_KEY_SECRET
macOS
在終端中執行以下命令,查看預設Shell類型。
echo $SHELL根據預設Shell類型進行操作。
Zsh
執行以下命令,將環境變數設定追加到
~/.zshrc檔案中。echo "export OSS_ACCESS_KEY_ID='YOUR_ACCESS_KEY_ID'" >> ~/.zshrc echo "export OSS_ACCESS_KEY_SECRET='YOUR_ACCESS_KEY_SECRET'" >> ~/.zshrc執行以下命令使變更生效。
source ~/.zshrc執行以下命令檢查環境變數是否生效。
echo $OSS_ACCESS_KEY_ID echo $OSS_ACCESS_KEY_SECRET
Bash
執行以下命令,將環境變數設定追加到
~/.bash_profile檔案中。echo "export OSS_ACCESS_KEY_ID='YOUR_ACCESS_KEY_ID'" >> ~/.bash_profile echo "export OSS_ACCESS_KEY_SECRET='YOUR_ACCESS_KEY_SECRET'" >> ~/.bash_profile執行以下命令使變更生效。
source ~/.bash_profile執行以下命令檢查環境變數是否生效。
echo $OSS_ACCESS_KEY_ID echo $OSS_ACCESS_KEY_SECRET
Windows
CMD
在CMD中運行以下命令。
setx OSS_ACCESS_KEY_ID "YOUR_ACCESS_KEY_ID" setx OSS_ACCESS_KEY_SECRET "YOUR_ACCESS_KEY_SECRET"運行以下命令,檢查環境變數是否生效。
echo %OSS_ACCESS_KEY_ID% echo %OSS_ACCESS_KEY_SECRET%
PowerShell
在PowerShell中運行以下命令。
[Environment]::SetEnvironmentVariable("OSS_ACCESS_KEY_ID", "YOUR_ACCESS_KEY_ID", [EnvironmentVariableTarget]::User) [Environment]::SetEnvironmentVariable("OSS_ACCESS_KEY_SECRET", "YOUR_ACCESS_KEY_SECRET", [EnvironmentVariableTarget]::User)運行以下命令,檢查環境變數是否生效。
[Environment]::GetEnvironmentVariable("OSS_ACCESS_KEY_ID", [EnvironmentVariableTarget]::User) [Environment]::GetEnvironmentVariable("OSS_ACCESS_KEY_SECRET", [EnvironmentVariableTarget]::User)
初始化用戶端
以下範例程式碼使用華東1(杭州)地區的外網訪問網域名稱初始化用戶端,並列舉該地區下的Bucket列表作為驗證。完整的地區和Endpoint列表請參見地區和Endpoint。
import com.aliyun.oss.*;
import com.aliyun.oss.common.auth.*;
import com.aliyun.oss.common.comm.SignVersion;
import com.aliyun.oss.model.Bucket;
import java.util.List;
/**
* OSS SDK 快速接入樣本
* 示範如何初始化 OSS 用戶端並列出所有 Bucket
*/
public class Test {
public static void main(String[] args) {
// 從環境變數擷取訪問憑證
String accessKeyId = System.getenv("OSS_ACCESS_KEY_ID");
String accessKeySecret = System.getenv("OSS_ACCESS_KEY_SECRET");
// 設定OSS地區和Endpoint
String region = "cn-hangzhou";
String endpoint = "oss-cn-hangzhou.aliyuncs.com";
// 建立憑證提供者
DefaultCredentialProvider provider = new DefaultCredentialProvider(accessKeyId, accessKeySecret);
// 配置用戶端參數
ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
// 顯式聲明使用V4簽名演算法
clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);
// 初始化OSS用戶端
OSS ossClient = OSSClientBuilder.create()
.credentialsProvider(provider)
.clientConfiguration(clientBuilderConfiguration)
.region(region)
.endpoint(endpoint)
.build();
// 列出目前使用者的所有Bucket
List<Bucket> buckets = ossClient.listBuckets();
System.out.println("成功串連到OSS服務,當前帳號下的Bucket列表:");
if (buckets.isEmpty()) {
System.out.println("當前帳號下暫無Bucket");
} else {
for (Bucket bucket : buckets) {
System.out.println("- " + bucket.getName());
}
}
// 釋放資源
ossClient.shutdown();
System.out.println("OSS用戶端已關閉");
}
}運行後將顯示當前帳號在所有地區下的 Bucket 列表:
成功串連到OSS服務,當前帳號下的Bucket列表:
- example-bucket
OSS用戶端已關閉用戶端配置
使用 ClientConfiguration 類配置 OSSClient 的逾時時間、重試次數、Proxy 伺服器等參數。
使用自訂網域名
使用OSS預設網域名稱訪問時,由於OSS的安全性原則限制,可能會出現檔案禁止訪問、無法直接預覽等問題。通過綁定自訂網域名訪問OSS,不僅可以繞過這些訪問限制,實現檔案的直接預覽,還能結合CDN服務實現Global Acceleration分發,提升使用者訪問體驗。
ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
// 開啟CNAME選項以支援自訂網域名訪問
clientBuilderConfiguration.setSupportCname(true);
OSS ossClient = new OSSClientBuilder()
// 其他配置...
.clientConfiguration(clientBuilderConfiguration)
// 使用您的自訂網域名作為Endpoint,例如 https://static.example.com
.endpoint("https://static.example.com")
.build();使用內網網域名稱
當應用程式部署在阿里雲ECS、Container Service或其他阿里雲產品上時,使用OSS內網網域名稱可以享受免費的內網流量傳輸,同時獲得更快的傳輸速度和更高的網路穩定性。內網訪問適用於大檔案上傳、批量資料處理和高頻訪問情境,有效降低成本並提升效能。完整的地區和內網Endpoint列表請參見地區和Endpoint。
ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
OSS ossClient = new OSSClientBuilder()
// 其他配置...
.clientConfiguration(clientBuilderConfiguration)
// 使用內網網域名稱,以華東1(杭州)為例,其他地區請按實際情況填寫
.endpoint("oss-cn-hangzhou-internal.aliyuncs.com")
.build();逾時控制
根據業務情境合理配置逾時參數。對於大檔案傳輸或網路環境不穩定的情境,建議適當增加逾時時間;對於高並發輕量級操作,可以設定較短的逾時時間以快速釋放資源。
ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
// 設定允許開啟的最大HTTP串連數,預設為1024
clientBuilderConfiguration.setMaxConnections(1024)
// 設定Socket層傳輸資料的逾時時間(單位:毫秒),預設為50000毫秒
.setSocketTimeout(50000)
// 設定建立串連的逾時時間(單位:毫秒),預設為50000毫秒
.setConnectionTimeout(50000)
// 設定從串連池中擷取串連的逾時時間(單位:毫秒),預設無逾時限制
.setConnectionRequestTimeout(60 * 60 * 24 * 1000)
// 設定串連空閑逾時時間,逾時則關閉串連(單位:毫秒),預設為60000毫秒
.setIdleConnectionTime(60000);
OSS ossClient = new OSSClientBuilder()
// 其他配置...
.clientConfiguration(clientBuilderConfiguration)
.build();最大錯誤重試次數
OSS用戶端預設重試3次以提升請求成功率。在高並發或網路不穩定環境下,適當使用 setMaxErrorRetry 增加重試次數可以顯著改善服務可用性,建議根據業務對延遲的容忍度和網路環境品質來調整重試次數。
ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
// 佈建要求失敗後的最大重試次數,根據網路環境和業務需求調整
clientBuilderConfiguration.setMaxErrorRetry(5);
OSS ossClient = new OSSClientBuilder()
// 其他配置...
.clientConfiguration(clientBuilderConfiguration)
.build();重試策略
不建議使用setRetryStrategy設定自訂重試策略,因為自訂策略可能導致不可預期的行為,影響服務穩定性。OSS用戶端針對不同請求類型採用經過驗證的重試策略:
POST 請求:預設不重試,避免重複提交導致的資料不一致。
非 POST 請求:在滿足以下條件時自動重試,最多重試3次。
ClientException異常,錯誤碼為:ConnectionTimeout、SocketTimeout、ConnectionRefused、UnknownHost、SocketException。OSSException異常,錯誤碼非InvalidResponse。HTTP 狀態代碼為 500、502 或 503 的服務端臨時錯誤。
Proxy 伺服器
商業網路環境通常通過Proxy 伺服器訪問外部資源以確保安全性。配置Proxy 伺服器後,OSS用戶端將通過指定的代理轉寄所有HTTP請求,實現安全的OSS服務訪問。
ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
// 設定使用者代理程式,指定HTTP的User-Agent頭,預設為aliyun-sdk-java
clientBuilderConfiguration.setUserAgent("aliyun-sdk-java");
// 設定Proxy 伺服器IP地址,請將""替換為實際的Proxy 伺服器IP(如"196.128.xxx.xxx")
clientBuilderConfiguration.setProxyHost("");
// 設定Proxy 伺服器訪問連接埠,例如8080連接埠
clientBuilderConfiguration.setProxyPort(8080);
// 設定Proxy 伺服器驗證的使用者名稱,請將""替換為實際的使用者名稱(如"admin")
clientBuilderConfiguration.setProxyUsername("");
// 設定Proxy 伺服器驗證的密碼,請將""替換為對應的驗證密碼
clientBuilderConfiguration.setProxyPassword("");
OSS ossClient = new OSSClientBuilder()
// 其他配置...
.clientConfiguration(clientBuilderConfiguration)
.build();HTTP/HTTPS 協議
通過 setProtocol 設定用戶端與OSS服務端的通訊協定。預設使用HTTP協議,生產環境強烈建議使用HTTPS協議以確保資料轉送安全,防止中間人攻擊和資料泄露。
ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
// 設定通訊協定為HTTPS,確保資料轉送安全
clientBuilderConfiguration.setProtocol(Protocol.HTTPS);
OSS ossClient = new OSSClientBuilder()
// 其他配置...
.clientConfiguration(clientBuilderConfiguration)
.build();簽名版本
阿里雲Object Storage Service V1 簽名將按以下時間錶停止使用,建議儘快升級至 V4 簽名,確保服務不受影響。
自 2025 年 3 月 1 日起,新註冊使用者無法使用 V1 簽名。
自 2025 年 9 月 1 日起,逐步停止 V1 簽名的更新維護,且新建立的 Bucket 無法使用 V1 簽名。
使用 setSignatureVersion 配置簽名演算法版本。使用 V4 簽名時,必須通過 region 參數指定正確的地區ID。V4簽名演算法提供更高的安全性,OSS Java SDK V1 3.15.0 及以上版本支援 V4 簽名。
ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
// 設定簽名演算法版本為V4,提供更高的安全性
clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);
OSS ossClient = new OSSClientBuilder()
// 其他配置...
// 使用V4簽名時必須指定地區ID
.region("cn-hangzhou")
.clientConfiguration(clientBuilderConfiguration)
.build();使用 IP 位址
使用IP地址作為Endpoint主要用於內網訪問和特殊網路環境情境。通過CEN、Express Connect、專線、VPN等方式建立網路連接後,可以使用IP地址直接存取OSS,繞過DNS解析過程提升訪問效率,具體路由配置可參考OSS內網網域名稱與VIP網段對照表。
ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
// 開啟次層網域訪問OSS,預設情況下是關閉的
// OSS Java SDK V1 2.1.2及之前的版本需要設定此值
// 2.1.2及之後的版本會自動檢測到IP地址,因此不再需要設定此值
clientBuilderConfiguration.setSLDEnabled(true);
OSS ossClient = new OSSClientBuilder()
// 其他配置...
.clientConfiguration(clientBuilderConfiguration)
// 使用IP地址訪問OSS時,建議使用HTTP協議以避免SSL認證校正問題
.endpoint("http://10.10.10.10")
.build();CRC 校正
OSS預設開啟CRC資料校正功能以保證資料轉送完整性,雖然會略微增加傳輸時間,但建議在生產環境中保持開啟以確保資料一致性。以下特定情境可考慮關閉CRC校正以提升傳輸效能:直播預覽流、IoT裝置即時資料、低品質監控視頻等可容忍少量資料丟失的即時業務,或在高可靠內網環境下的批量資料轉送。關閉CRC校正前,請充分評估資料一致性風險並進行完整的測實驗證。
ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
// 關閉CRC資料校正功能,請謹慎使用並充分評估風險
clientBuilderConfiguration.setCrcCheckEnabled(false);
OSS ossClient = new OSSClientBuilder()
// 其他配置...
.clientConfiguration(clientBuilderConfiguration)
.build();單例模式
OSS Java SDK V1 推薦採用單例模式來建立和使用 OSSClient 執行個體。
OSSClient 具備安全執行緒特性,支援多線程並發訪問同一執行個體。結合業務需求,採用單例模式建立並複用 OSSClient 執行個體,可以避免頻繁建立銷毀執行個體的開銷。
OSSClient 執行個體內部維護串連池,當確定 OSSClient 執行個體不再使用時,調用 shutdown 方法關閉執行個體,防止建立過多執行個體導致系統資源耗盡。
import com.aliyun.oss.ClientBuilderConfiguration;
import com.aliyun.oss.OSS;
import com.aliyun.oss.*;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.common.auth.CredentialsProvider;
import com.aliyun.oss.common.auth.CredentialsProviderFactory;
import com.aliyun.oss.common.comm.SignVersion;
import com.aliyun.oss.internal.OSSHeaders;
import com.aliyun.oss.model.*;
import java.io.ByteArrayInputStream;
public class OssClientSingleton {
private OssClientSingleton() {}
// 靜態內部類實現單例(安全執行緒)
private static class SingletonHolder {
private static final OSS INSTANCE = create();
private static OSS create() {
try {
// Endpoint以華東1(杭州)為例,其它Region請按實際情況填寫。
String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
// 填寫Bucket所在地區。以華東1(杭州)為例,Region填寫為cn-hangzhou。
String region = "cn-hangzhou";
ClientBuilderConfiguration config = new ClientBuilderConfiguration();
// 顯式聲明使用 V4 簽名演算法
config.setSignatureVersion(SignVersion.V4);
//從環境變數中擷取訪問憑證。運行本程式碼範例之前,請確保已設定環境變數OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
CredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
// 構建OSS用戶端
return OSSClientBuilder.create()
.endpoint(endpoint)
.credentialsProvider(credentialsProvider)
.clientConfiguration(config)
.region(region)
.build();
} catch (Exception e) {
throw new RuntimeException("OSS用戶端初始化失敗", e);
}
}
}
// 擷取單例執行個體
public static OSS getInstance() {
return SingletonHolder.INSTANCE;
}
// 主函數測試PutObject操作
public static void main(String[] args) {
// 擷取單例OSS用戶端
OSS ossClient = OssClientSingleton.getInstance();
// 填寫Bucket名稱,例如examplebucket。
String bucketName = "examplebucket";
// 填寫不包含Bucket名稱在內的Object完整路徑,例如testfolder/exampleobject.txt。
String objectKey = "testfolder/exampleobject.txt";
try {
// 填寫字串。
String content = "Hello OSS";
// 建立PutObjectRequest對象。
PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectKey, new ByteArrayInputStream(content.getBytes()));
// 如果需要上傳時設定儲存類型和存取權限,請參考以下範例程式碼。
ObjectMetadata metadata = new ObjectMetadata();
metadata.setHeader(OSSHeaders.OSS_STORAGE_CLASS, StorageClass.Standard.toString());
metadata.setObjectAcl(CannedAccessControlList.Private);
putObjectRequest.setMetadata(metadata);
// 上傳字串。
PutObjectResult result = ossClient.putObject(putObjectRequest);
// 列印上傳結果。
System.out.println("檔案上傳成功!");
System.out.println("ETag: " + result.getETag());
System.out.println("請求ID: " + result.getRequestId());
} catch (OSSException oe) {
System.out.println("Caught an OSSException, which means your request made it to OSS, "
+ "but was rejected with an error response for some reason.");
System.out.println("Error Message:" + oe.getErrorMessage());
System.out.println("Error Code:" + oe.getErrorCode());
System.out.println("Request ID:" + oe.getRequestId());
System.out.println("Host ID:" + oe.getHostId());
} catch (ClientException ce) {
System.out.println("Caught an ClientException, which means the client encountered "
+ "a serious internal problem while trying to communicate with OSS, "
+ "such as not being able to access the network.");
System.out.println("Error Message:" + ce.getMessage());
} finally {
// 在單例模式下,不建議在每次操作後關閉client(保持串連複用),避免影響後續使用。
// 在明確OSSClient執行個體不再使用時(例如應用程式退出前),調用一次shutdown方法以釋放資源。
// ossClient.shutdown();
}
}
}
異常處理
OSS Java SDK V1包含兩類異常:ClientException和OSSException,均繼承自RuntimeException。
用戶端異常(ClientException)
用戶端異常指在構建請求、發送請求或傳輸資料過程中發生的異常。常見情境包括:
網路連接不可用,導致請求無法發送到服務端。
上傳檔案時發生 IO 異常。
請求逾時、認證驗證失敗等底層網路異常。
拋出ClientException表示請求未成功發送至OSS服務端,或在用戶端處理過程中出現錯誤,通常需要檢查網路連接狀態、用戶端配置或重試機制。
服務端異常(OSSException)
服務端異常表示OSS服務端返回的異常資訊,即請求已成功發送並被服務端接收,但由於某些原因未能正常處理。OSS服務端異常具有以下特點:
包含詳細的錯誤碼(ErrorCode)和錯誤資訊(ErrorMessage),便於精確定位問題。
常見錯誤包括簽名不匹配(SignatureDoesNotMatch)、許可權不足(AccessDenied)、資源不存在(NoSuchKey)等。
通過錯誤碼進行針對性處理,可以顯著提升程式的健壯性和使用者體驗。
在實際開發中建議對這兩類異常分別進行捕獲,以便更準確地判斷問題來源並制定相應的處理策略。
// 建立用戶端的操作...
try {
// 執行OSS操作,例如上傳檔案、下載檔案、列舉對象等
// 這裡的操作可能會拋出OSS相關的異常
ossClient.putObject(...);
} catch (OSSException oe) {
// 捕獲OSS服務端返回的異常
// 當請求成功到達OSS服務端,但服務端拒絕執行請求時拋出此異常
// 常見原因:許可權不足、參數錯誤、資源不存在等
System.out.println("Caught an OSSException, which means your request made it to OSS, "
+ "but was rejected with an error response for some reason.");
// 輸出詳細的錯誤資訊,便於問題定位和調試
System.out.println("Error Message: " + oe.getErrorMessage());
System.out.println("Error Code: " + oe.getErrorCode());
System.out.println("Request ID: " + oe.getRequestId());
System.out.println("Host ID: " + oe.getHostId());
} catch (ClientException ce) {
// 捕獲用戶端異常
// 當用戶端在與OSS通訊過程中遇到嚴重內部問題時拋出此異常
// 常見原因:網路連接問題、SSL認證問題、DNS解析失敗等
System.out.println("Caught an ClientException, which means the client encountered "
+ "a serious internal problem while trying to communicate with OSS, "
+ "such as not being able to access the network.");
// 輸出用戶端異常的詳細資料
System.out.println("Error Message: " + ce.getMessage());
} finally {
// 無論操作成功或失敗,都需要釋放用戶端資源
// 這是最佳實務,避免資源泄漏和串連池耗盡
if (ossClient != null) {
ossClient.shutdown(); // 關閉用戶端,釋放網路連接等資源
}
}範例程式碼
OSS Java SDK V1提供豐富的範例程式碼,涵蓋儲存空間管理、檔案操作、許可權控制、加密傳輸等核心功能,便於參考或直接使用。範例程式碼包括以下內容:
樣本檔案 | 樣本內容 |
說明 PostObject的實現不依賴Java SDK。 | |
訪問憑證配置
OSS 支援多種憑證初始化方式,需根據認證和授權需求選擇合適的初始化方式。
使用RAM使用者的AK
適用於應用程式部署運行在安全、穩定且不易受外部攻擊的環境中,需要長期訪問OSS且無法頻繁輪轉憑證的情境。通過阿里雲主帳號或RAM使用者的AK(Access Key ID、Access Key Secret)初始化憑證提供者。該方式需要手動維護AK,存在安全性風險和維護複雜度增加的風險。
阿里雲帳號擁有資源的全部許可權,AK一旦泄露,會給系統帶來巨大風險,不建議使用。推薦使用最小化授權的RAM使用者的AK。
如需建立RAM使用者的AK,請直接存取建立AccessKey。RAM使用者的Access Key ID、Access Key Secret資訊僅在建立時顯示,如若遺忘請建立新的AK進行替換。
環境變數
使用RAM使用者AccessKey配置環境變數。
Linux
在命令列介面執行以下命令,將環境變數設定追加到
~/.bashrc檔案中。echo "export OSS_ACCESS_KEY_ID='YOUR_ACCESS_KEY_ID'" >> ~/.bashrc echo "export OSS_ACCESS_KEY_SECRET='YOUR_ACCESS_KEY_SECRET'" >> ~/.bashrc執行以下命令使變更生效。
source ~/.bashrc執行以下命令檢查環境變數是否生效。
echo $OSS_ACCESS_KEY_ID echo $OSS_ACCESS_KEY_SECRET
macOS
在終端中執行以下命令,查看預設Shell類型。
echo $SHELL根據預設Shell類型進行操作。
Zsh
執行以下命令,將環境變數設定追加到
~/.zshrc檔案中。echo "export OSS_ACCESS_KEY_ID='YOUR_ACCESS_KEY_ID'" >> ~/.zshrc echo "export OSS_ACCESS_KEY_SECRET='YOUR_ACCESS_KEY_SECRET'" >> ~/.zshrc執行以下命令使變更生效。
source ~/.zshrc執行以下命令檢查環境變數是否生效。
echo $OSS_ACCESS_KEY_ID echo $OSS_ACCESS_KEY_SECRET
Bash
執行以下命令,將環境變數設定追加到
~/.bash_profile檔案中。echo "export OSS_ACCESS_KEY_ID='YOUR_ACCESS_KEY_ID'" >> ~/.bash_profile echo "export OSS_ACCESS_KEY_SECRET='YOUR_ACCESS_KEY_SECRET'" >> ~/.bash_profile執行以下命令使變更生效。
source ~/.bash_profile執行以下命令檢查環境變數是否生效。
echo $OSS_ACCESS_KEY_ID echo $OSS_ACCESS_KEY_SECRET
Windows
CMD
在CMD中運行以下命令。
setx OSS_ACCESS_KEY_ID "YOUR_ACCESS_KEY_ID" setx OSS_ACCESS_KEY_SECRET "YOUR_ACCESS_KEY_SECRET"運行以下命令,檢查環境變數是否生效。
echo %OSS_ACCESS_KEY_ID% echo %OSS_ACCESS_KEY_SECRET%
PowerShell
在PowerShell中運行以下命令。
[Environment]::SetEnvironmentVariable("OSS_ACCESS_KEY_ID", "YOUR_ACCESS_KEY_ID", [EnvironmentVariableTarget]::User) [Environment]::SetEnvironmentVariable("OSS_ACCESS_KEY_SECRET", "YOUR_ACCESS_KEY_SECRET", [EnvironmentVariableTarget]::User)運行以下命令,檢查環境變數是否生效。
[Environment]::GetEnvironmentVariable("OSS_ACCESS_KEY_ID", [EnvironmentVariableTarget]::User) [Environment]::GetEnvironmentVariable("OSS_ACCESS_KEY_SECRET", [EnvironmentVariableTarget]::User)
參考上述方式修改系統內容變數後,需重啟或重新整理編譯運行環境,包括IDE、命令列介面、其他傳統型應用程式及後台服務,以確保最新的系統內容變數成功載入。
使用環境變數傳遞憑證資訊。
import com.aliyun.oss.ClientBuilderConfiguration; import com.aliyun.oss.OSS; import com.aliyun.oss.OSSClientBuilder; import com.aliyun.oss.common.auth.CredentialsProviderFactory; import com.aliyun.oss.common.auth.EnvironmentVariableCredentialsProvider; import com.aliyun.oss.common.comm.SignVersion; public class AkDemoTest { public static void main(String[] args) throws Exception { // 從環境變數中擷取憑證 EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider(); // 使用credentialsProvider進行後續操作... ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration(); clientBuilderConfiguration.setSignatureVersion(SignVersion.V4); // 建立OSSClient執行個體。 // 當OSSClient執行個體不再使用時,調用shutdown方法以釋放資源。 OSS ossClient = OSSClientBuilder.create() .endpoint("endpoint") .credentialsProvider(credentialsProvider) .clientConfiguration(clientBuilderConfiguration) .region("region") .build(); ossClient.shutdown(); } }
靜態憑證
以下範例程式碼展示了對訪問憑據直接進行寫入程式碼,顯式設定要使用的存取金鑰的方法。
請勿將訪問憑據嵌入到生產環境的應用程式中,此方法僅用於測試目的。
import com.aliyun.oss.ClientBuilderConfiguration;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.common.auth.CredentialsProvider;
import com.aliyun.oss.common.auth.DefaultCredentialProvider;
import com.aliyun.oss.common.comm.SignVersion;
public class AkDemoTest {
public static void main(String[] args) throws Exception {
// 填寫RAM使用者的Access Key ID和Access Key Secret
String accessKeyId = "yourAccessKeyID";
String accessKeySecret = "yourAccessKeySecret";
// 使用DefaultCredentialProvider方法直接設定AK和SK
CredentialsProvider credentialsProvider = new DefaultCredentialProvider(accessKeyId, accessKeySecret);
// 使用credentialsProvider初始化用戶端
ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
// 顯式聲明使用 V4 簽名演算法
clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);
// 建立OSSClient執行個體。
// 當OSSClient執行個體不再使用時,調用shutdown方法以釋放資源。
OSS ossClient = OSSClientBuilder.create()
.endpoint("endpoint")
.credentialsProvider(credentialsProvider)
.clientConfiguration(clientBuilderConfiguration)
.region("region")
.build();
ossClient.shutdown();
}
}使用STS臨時訪問憑證
適用於應用程式需要臨時訪問OSS的情境。通過STS服務擷取的臨時身份憑證(Access Key ID、Access Key Secret和Security Token)初始化憑證提供者。該方式需要手動維護STS Token,存在安全性風險和維護複雜度增加的風險。如果需要多次臨時訪問OSS,需要手動重新整理STS Token。
通過OpenAPI方式簡單快速擷取STS臨時訪問憑證,請參見AssumeRole - 擷取扮演角色的臨時身份憑證。
通過SDK方式擷取STS臨時訪問憑證,請參見使用STS臨時訪問憑證訪問OSS。
請注意,STS Token在產生的時候需要指定到期時間,到期後自動失效不能再使用。
擷取關於STS服務的存取點列表,請參見服務存取點。
環境變數
使用臨時身份憑證設定環境變數。
Mac OS/Linux/Unix
重要請注意,此處使用的是通過STS服務擷取的臨時身份憑證(Access Key ID、Access Key Secret和Security Token),而非RAM使用者的Access Key和Access Key Secret。
請注意區分STS服務擷取的Access Key ID以STS開頭,例如“STS.****************”。
export OSS_ACCESS_KEY_ID=<STS_ACCESS_KEY_ID> export OSS_ACCESS_KEY_SECRET=<STS_ACCESS_KEY_SECRET> export OSS_SESSION_TOKEN=<STS_SECURITY_TOKEN>Windows
重要請注意,此處使用的是通過STS服務擷取的臨時身份憑證(Access Key ID、Access Key Secret和Security Token),而非RAM使用者的AK(Access Key ID、Access Key Secret)。
請注意區分STS服務擷取的Access Key ID以STS開頭,例如“STS.****************”。
set OSS_ACCESS_KEY_ID=<STS_ACCESS_KEY_ID> set OSS_ACCESS_KEY_SECRET=<STS_ACCESS_KEY_SECRET> set OSS_SESSION_TOKEN=<STS_SECURITY_TOKEN>通過環境變數傳遞憑證資訊。
import com.aliyun.oss.ClientBuilderConfiguration; import com.aliyun.oss.OSS; import com.aliyun.oss.OSSClientBuilder; import com.aliyun.oss.common.auth.CredentialsProviderFactory; import com.aliyun.oss.common.auth.EnvironmentVariableCredentialsProvider; import com.aliyun.oss.common.comm.SignVersion; public class StsDemoTest { public static void main(String[] args) throws Exception { // 從環境變數中擷取憑證 EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider(); // 使用credentialsProvider初始化用戶端 ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration(); // 顯式聲明使用 V4 簽名演算法 clientBuilderConfiguration.setSignatureVersion(SignVersion.V4); // 建立OSSClient執行個體。 // 當OSSClient執行個體不再使用時,調用shutdown方法以釋放資源。 OSS ossClient = OSSClientBuilder.create() .endpoint("endpoint") .credentialsProvider(credentialsProvider) .clientConfiguration(clientBuilderConfiguration) .region("region") .build(); ossClient.shutdown(); } }
靜態憑證
可以在應用程式中對憑據直接進行寫入程式碼,顯式設定要使用的臨時存取金鑰。
import com.aliyun.oss.ClientBuilderConfiguration;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.common.auth.CredentialsProvider;
import com.aliyun.oss.common.auth.DefaultCredentialProvider;
import com.aliyun.oss.common.comm.SignVersion;
public class StsDemoTest {
public static void main(String[] args) throws Exception {
// 請設定為您通過STS服務擷取的臨時身份憑證Access Key ID、Access Key Secret和Security Token,而非RAM使用者的身份憑證資訊
// 請注意區分STS服務擷取的Access Key ID是以STS開頭,如下所示
String accessKeyId = "STS.****************";
String accessKeySecret = "yourAccessKeySecret";
String stsToken= "yourSecurityToken";
// 使用DefaultCredentialProvider方法直接設定AK和SK
CredentialsProvider credentialsProvider = new DefaultCredentialProvider(accessKeyId, accessKeySecret, stsToken);
// 使用credentialsProvider初始化用戶端
ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
// 顯式聲明使用 V4 簽名演算法
clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);
// 建立OSSClient執行個體。
// 當OSSClient執行個體不再使用時,調用shutdown方法以釋放資源。
OSS ossClient = OSSClientBuilder.create()
.endpoint("endpoint")
.credentialsProvider(credentialsProvider)
.clientConfiguration(clientBuilderConfiguration)
.region("region")
.build();
ossClient.shutdown();
}
}使用RAMRoleARN
適用於應用程式需要授權訪問OSS,例如跨阿里雲帳號訪問OSS的情境。通過指定RAM角色的ARN(Alibabacloud Resource Name)初始化憑證提供者,底層實現基於STS Token。Credentials工具會前往STS服務擷取STS Token,並在會話到期前調用AssumeRole介面申請新的STS Token。還可以通過為policy賦值來限制RAM角色到一個更小的許可權集合。
阿里雲帳號擁有資源的全部許可權,AK一旦泄露,會給系統帶來巨大風險,不建議使用。推薦使用最小化授權的RAM使用者的AK。
如需建立RAM使用者的AK,請直接存取建立AccessKey。RAM使用者的Access Key ID、Access Key Secret資訊僅在建立時顯示,請及時儲存,如若遺忘請建立新的AK進行輪換。
如需擷取RAMRoleARN,請直接存取CreateRole - 建立角色。
添加credentials依賴。
<!-- https://mvnrepository.com/artifact/com.aliyun/credentials-java --> <dependency> <groupId>com.aliyun</groupId> <artifactId>credentials-java</artifactId> <version>LATEST</version> </dependency>配置AK和RAMRoleARN作為訪問憑證。
import com.aliyun.credentials.models.CredentialModel; import com.aliyun.oss.ClientBuilderConfiguration; import com.aliyun.oss.OSS; import com.aliyun.oss.OSSClientBuilder; import com.aliyun.oss.common.auth.Credentials; import com.aliyun.oss.common.auth.CredentialsProvider; import com.aliyun.oss.common.auth.DefaultCredentials; import com.aliyun.oss.common.comm.SignVersion; public class RamRoleArnAkDemoTest { public static void main(String[] args) { com.aliyun.credentials.models.Config config = new com.aliyun.credentials.models.Config(); // 訪問憑證類型。固定為ram_role_arn config.setType("ram_role_arn"); // 要扮演的RAM角色ARN,樣本值:acs:ram::123456789012****:role/adminrole,可以通過環境變數ALIBABA_CLOUD_ROLE_ARN設定RoleArn config.setRoleArn("<RoleArn>"); // 從環境變數中擷取AccessKeyId config.setAccessKeyId(System.getenv().get("ALIBABA_CLOUD_ACCESS_KEY_ID")); // 從環境變數中擷取AccessKeySecret config.setAccessKeySecret(System.getenv().get("ALIBABA_CLOUD_ACCESS_KEY_SECRET")); // 角色會話名稱,可以通過環境變數ALIBABA_CLOUD_ROLE_SESSION_NAME設定RoleSessionName config.setRoleName("<RoleSessionName>"); // 設定更小的權限原則,非必填。樣本值:{"Statement": [{"Action": ["*"],"Effect": "Allow","Resource": ["*"]}],"Version":"1"} config.setPolicy("<Policy>"); // 設定角色會話有效期間,非必填 config.setRoleSessionExpiration(3600); final com.aliyun.credentials.Client credentialsClient = new com.aliyun.credentials.Client(config); CredentialsProvider credentialsProvider = new CredentialsProvider(){ @Override public void setCredentials(Credentials credentials) { } @Override public Credentials getCredentials() { CredentialModel credential = credentialsClient.getCredential(); return new DefaultCredentials(credential.getAccessKeyId(), credential.getAccessKeySecret(), credential.getSecurityToken()); } }; // 使用credentialsProvider初始化用戶端 ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration(); // 顯式聲明使用 V4 簽名演算法 clientBuilderConfiguration.setSignatureVersion(SignVersion.V4); // 建立OSSClient執行個體。 // 當OSSClient執行個體不再使用時,調用shutdown方法以釋放資源。 OSS ossClient = OSSClientBuilder.create() .endpoint("endpoint") .credentialsProvider(credentialsProvider) .clientConfiguration(clientBuilderConfiguration) .region("region") .build(); ossClient.shutdown(); } }
使用ECSRAMRole
適用於應用程式運行在ECS執行個體、ECI執行個體、Container ServiceKubernetes版的Worker節點中的情境。建議使用ECSRAMRole初始化憑證提供者,底層實現基於STS Token。ECSRAMRole允許將一個角色關聯到ECS執行個體、ECI執行個體或Container Service Kubernetes 版的Worker節點,實現在執行個體內部自動重新整理STS Token。該方式無需提供AK或STS Token,消除了手動維護AK或STS Token的風險。如何擷取ECSRAMRole,請參見CreateRole - 建立角色。如何將一個角色關聯到ECS執行個體,請參見執行個體RAM角色。
添加credentials依賴。
<!-- https://mvnrepository.com/artifact/com.aliyun/credentials-java --> <dependency> <groupId>com.aliyun</groupId> <artifactId>credentials-java</artifactId> <version>LATEST</version> </dependency>配置ECSRAMRole作為訪問憑證。
import com.aliyun.credentials.models.CredentialModel; import com.aliyun.oss.ClientBuilderConfiguration; import com.aliyun.oss.OSS; import com.aliyun.oss.OSSClientBuilder; import com.aliyun.oss.common.auth.Credentials; import com.aliyun.oss.common.auth.CredentialsProvider; import com.aliyun.oss.common.auth.DefaultCredentials; import com.aliyun.oss.common.comm.SignVersion; public class EcsRamRoleDemoTest { public static void main(String[] args) { com.aliyun.credentials.models.Config config = new com.aliyun.credentials.models.Config(); // 訪問憑證類型。固定為ecs_ram_role。 config.setType("ecs_ram_role"); // 為ECS執行個體分配的RAM角色名稱。 config.setRoleName("<RoleName>"); final com.aliyun.credentials.Client credentialsClient = new com.aliyun.credentials.Client(config); CredentialsProvider credentialsProvider = new CredentialsProvider(){ @Override public void setCredentials(Credentials credentials) { } @Override public Credentials getCredentials() { CredentialModel credential = credentialsClient.getCredential(); return new DefaultCredentials(credential.getAccessKeyId(), credential.getAccessKeySecret(), credential.getSecurityToken()); } }; // 使用credentialsProvider初始化用戶端 ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration(); // 顯式聲明使用 V4 簽名演算法 clientBuilderConfiguration.setSignatureVersion(SignVersion.V4); // 建立OSSClient執行個體。 // 當OSSClient執行個體不再使用時,調用shutdown方法以釋放資源。 OSS ossClient = OSSClientBuilder.create() .endpoint("endpoint") .credentialsProvider(credentialsProvider) .clientConfiguration(clientBuilderConfiguration) .region("region") .build(); ossClient.shutdown(); } }
使用OIDCRoleARN
在Container ServiceKubernetes版中設定了Worker節點RAM角色後,對應節點內的Pod中的應用也可以像ECS上部署的應用一樣,通過中繼資料服務(Meta Data Server)擷取關聯角色的STS Token。但如果容器叢集上部署的是不可信的應用(比如部署客戶提交的應用,代碼也沒有開放),可能並不希望它們能通過中繼資料服務擷取Worker節點關聯執行個體RAM角色的STS Token。為了避免影響雲上資源的安全,同時又能讓這些不可信的應用安全地擷取所需的STS Token,實現應用層級的許可權最小化,可以使用RRSA(RAM Roles for Service Account)功能。該方式底層實現基於STS Token。阿里雲容器叢集會為不同的應用Pod建立和掛載相應的服務賬戶OIDC Token檔案,並將相關配置資訊注入到環境變數中,Credentials工具通過擷取環境變數的配置資訊,調用STS服務的AssumeRoleWithOIDC介面換取綁定角色的STS Token。該方式無需提供AK或STS Token,消除了手動維護AK或STS Token的風險。詳情請參見基於RRSA的Pod許可權隔離。
添加credentials依賴。
<!-- https://mvnrepository.com/artifact/com.aliyun/credentials-java --> <dependency> <groupId>com.aliyun</groupId> <artifactId>credentials-java</artifactId> <version>LATEST</version> </dependency>配置OIDC的RAM角色作為訪問憑證。
import com.aliyun.credentials.models.CredentialModel; import com.aliyun.oss.ClientBuilderConfiguration; import com.aliyun.oss.OSS; import com.aliyun.oss.OSSClientBuilder; import com.aliyun.oss.common.auth.Credentials; import com.aliyun.oss.common.auth.CredentialsProvider; import com.aliyun.oss.common.auth.DefaultCredentials; import com.aliyun.oss.common.comm.SignVersion; public class OidcRoleArnDemoTest { public static void main(String[] args) { com.aliyun.credentials.models.Config config = new com.aliyun.credentials.models.Config(); // 指定Credential類型,固定值為oidc_role_arn config.setType("oidc_role_arn"); // RAM角色名稱ARN,可以通過環境變數ALIBABA_CLOUD_ROLE_ARN設定RoleArn config.setRoleArn("<RoleArn>"); // OIDC供應商ARN,可以通過環境變數ALIBABA_CLOUD_OIDC_PROVIDER_ARN設定OidcProviderArn config.setOidcProviderArn("<OidcProviderArn>"); // OIDC Token檔案路徑,可以通過環境變數ALIBABA_CLOUD_OIDC_TOKEN_FILE設定OidcTokenFilePath config.setOidcTokenFilePath("<OidcTokenFilePath>"); // 角色會話名稱,可以通過環境變數ALIBABA_CLOUD_ROLE_SESSION_NAME設定RoleSessionName config.setRoleSessionName("<RoleSessionName>"); // 設定更小的權限原則,非必填。樣本值:{"Statement": [{"Action": ["*"],"Effect": "Allow","Resource": ["*"]}],"Version":"1"} config.setPolicy("<Policy>"); // 設定session到期時間 config.setRoleSessionExpiration(3600); final com.aliyun.credentials.Client credentialsClient = new com.aliyun.credentials.Client(config); CredentialsProvider credentialsProvider = new CredentialsProvider(){ @Override public void setCredentials(Credentials credentials) { } @Override public Credentials getCredentials() { CredentialModel credential = credentialsClient.getCredential(); return new DefaultCredentials(credential.getAccessKeyId(), credential.getAccessKeySecret(), credential.getSecurityToken()); } }; // 使用credentialsProvider初始化用戶端 ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration(); // 顯式聲明使用 V4 簽名演算法 clientBuilderConfiguration.setSignatureVersion(SignVersion.V4); // 建立OSSClient執行個體。 // 當OSSClient執行個體不再使用時,調用shutdown方法以釋放資源。 OSS ossClient = OSSClientBuilder.create() .endpoint("endpoint") .credentialsProvider(credentialsProvider) .clientConfiguration(clientBuilderConfiguration) .region("region") .build(); ossClient.shutdown(); } }
使用Function Compute上下文中的Credentials
適用於應用程式的函數部署運行在Function Compute中的情境。可以使用Function Compute上下文中的Credentials初始化憑證提供者,底層實現基於STS Token。Function Compute根據函數配置的角色,通過扮演服務角色擷取一個STS Token,然後通過上下文中的參數Credentials將STS Token傳遞給應用程式。該STS Token的有效期間為36小時,且不支援修改。函數的最大執行時間為24小時,因此,執行函數過程中,STS Token不會到期,無需考慮重新整理問題。該方式無需提供AK或STS Token,消除了手動維護AK或STS Token的風險。如何授予Function Compute訪問OSS的許可權,請參見使用函數角色授予Function Compute訪問其他雲端服務的許可權。
添加Function Compute上下文依賴。
<!-- https://mvnrepository.com/artifact/com.aliyun.fc.runtime/fc-java-core --> <dependency> <groupId>com.aliyun.fc.runtime</groupId> <artifactId>fc-java-core</artifactId> <version>1.4.1</version> </dependency>使用Function Compute上下文中的Credentials初始化憑證提供者。
import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import com.aliyun.fc.runtime.Context; import com.aliyun.fc.runtime.Credentials; import com.aliyun.fc.runtime.StreamRequestHandler; import com.aliyun.oss.ClientBuilderConfiguration; import com.aliyun.oss.OSS; import com.aliyun.oss.OSSClientBuilder; import com.aliyun.oss.common.auth.*; import com.aliyun.oss.common.comm.SignVersion; public class App implements StreamRequestHandler { @Override public void handleRequest( InputStream inputStream, OutputStream outputStream, Context context) throws IOException { // 擷取密鑰資訊,執行前,確保函數所在的服務配置了角色資訊,並且角色需要擁有相關OSS許可權,建議直接使用AliyunFCDefaultRole角色 Credentials creds = context.getExecutionCredentials(); // 使用擷取到的憑證建立憑證提供者執行個體 CredentialsProvider credentialsProvider = new DefaultCredentialProvider(creds.getAccessKeyId(), creds.getAccessKeySecret(), creds.getSecurityToken()); // 使用credentialsProvider初始化用戶端 ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration(); // 顯式聲明使用 V4 簽名演算法 clientBuilderConfiguration.setSignatureVersion(SignVersion.V4); // 建立OSSClient執行個體。 // 當OSSClient執行個體不再使用時,調用shutdown方法以釋放資源。 OSS ossClient = OSSClientBuilder.create() .endpoint("endpoint") .credentialsProvider(credentialsProvider) .clientConfiguration(clientBuilderConfiguration) .region("region") .build(); ossClient.shutdown(); outputStream.write(new String("done").getBytes()); } }
使用CredentialsURI
適用於應用程式需要通過外部系統擷取阿里雲憑證,從而實現靈活的憑證管理和無密鑰訪問的情境。可以使用CredentialsURI初始化憑證提供者,底層實現基於STS Token。Credentials工具通過提供的URI擷取STS Token,完成憑證用戶端初始化。該方式無需提供AK或STS Token,消除了手動維護AK或STS Token的風險。
為了使Credentials工具正確解析和使用STS Token,URI必須遵循以下響應協議:
響應狀態代碼:200
響應體結構:
{ "Code": "Success", "AccessKeySecret": "AccessKeySecret", "AccessKeyId": "AccessKeyId", "Expiration": "2021-09-26T03:46:38Z", "SecurityToken": "SecurityToken" }
添加credentials依賴。
<!-- https://mvnrepository.com/artifact/com.aliyun/credentials-java --> <dependency> <groupId>com.aliyun</groupId> <artifactId>credentials-java</artifactId> <version>LATEST</version> </dependency>配置CredentialsURI作為訪問憑證。
import com.aliyun.credentials.models.CredentialModel; import com.aliyun.oss.ClientBuilderConfiguration; import com.aliyun.oss.OSS; import com.aliyun.oss.OSSClientBuilder; import com.aliyun.oss.common.auth.Credentials; import com.aliyun.oss.common.auth.CredentialsProvider; import com.aliyun.oss.common.auth.DefaultCredentials; import com.aliyun.oss.common.comm.SignVersion; public class CredentialsUriDemoTest { public static void main(String[] args) { com.aliyun.credentials.models.Config config = new com.aliyun.credentials.models.Config(); // 訪問憑證類型。固定為credentials_uri config.setType("credentials_uri"); // 憑證的 URI,即您產生STS Token的伺服器位址,格式為http://local_or_remote_uri/,可以通過環境變數ALIBABA_CLOUD_CREDENTIALS_URI設定CredentialsUri config.setCredentialsUri("<CredentialsUri>"); final com.aliyun.credentials.Client credentialsClient = new com.aliyun.credentials.Client(config); CredentialsProvider credentialsProvider = new CredentialsProvider(){ @Override public void setCredentials(Credentials credentials) { } @Override public Credentials getCredentials() { CredentialModel credential = credentialsClient.getCredential(); return new DefaultCredentials(credential.getAccessKeyId(), credential.getAccessKeySecret(), credential.getSecurityToken()); } }; // 使用credentialsProvider初始化用戶端 ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration(); // 顯式聲明使用 V4 簽名演算法 clientBuilderConfiguration.setSignatureVersion(SignVersion.V4); // 建立OSSClient執行個體。 // 當OSSClient執行個體不再使用時,調用shutdown方法以釋放資源。 OSS ossClient = OSSClientBuilder.create() .endpoint("endpoint") .credentialsProvider(credentialsProvider) .clientConfiguration(clientBuilderConfiguration) .region("region") .build(); ossClient.shutdown(); } }
使用自動輪轉的AK
適用於應用程式需要長期訪問OSS,但部署啟動並執行環境面臨AK泄露風險,需要頻繁手動輪轉(輪換)AK的情境。可以使用ClientKey初始化憑證提供者,底層實現基於AK。使用ClientKey後,Key Management Service(KMS)可以對託管的RAM使用者AK進行全自動的定期輪轉,將靜態RAM使用者AK動態化,從而降低AK泄漏的風險。除定期輪轉外,KMS還支援立即輪轉,在AK泄漏情況下快速更換AK。該方式無需手動維護AK,從而降低安全性風險和維護複雜度。如何擷取ClientKey,請參見建立應用存取點。
添加憑據用戶端依賴。
<!-- https://mvnrepository.com/artifact/com.aliyun/alibabacloud-secretsmanager-client --> <dependency> <groupId>com.aliyun</groupId> <artifactId>alibabacloud-secretsmanager-client</artifactId> <version>1.3.7</version> </dependency> <!-- https://mvnrepository.com/artifact/com.aliyun/aliyun-java-sdk-core --> <dependency> <groupId>com.aliyun</groupId> <artifactId>aliyun-java-sdk-core</artifactId> <version>4.7.0</version> </dependency>建立設定檔
secretsmanager.properties。# 訪問憑據類型,固定為client_key credentials_type=client_key # 讀取Client Key的解密密碼:支援從環境變數或者檔案讀取,只需設定一種 client_key_password_from_env_variable=<your client key private key password environment variable name> client_key_password_from_file_path=<your client key private key password file path> # Client Key的私密金鑰檔案路徑 client_key_private_key_path=<your client key private key file path> # 關聯的KMS服務地區 cache_client_region_id=[{"regionId":"<regionId>"}]使用設定檔傳遞憑證資訊。
import com.aliyun.oss.ClientBuilderConfiguration; import com.aliyun.oss.OSS; import com.aliyun.oss.OSSClientBuilder; import com.aliyun.oss.common.auth.Credentials; import com.aliyun.oss.common.auth.CredentialsProvider; import com.aliyun.oss.common.auth.DefaultCredentials; import com.aliyun.oss.common.comm.SignVersion; import com.aliyuncs.kms.secretsmanager.client.SecretCacheClient; import com.aliyuncs.kms.secretsmanager.client.SecretCacheClientBuilder; import com.aliyuncs.kms.secretsmanager.client.exception.CacheSecretException; import com.aliyuncs.kms.secretsmanager.client.model.SecretInfo; import org.codehaus.jettison.json.JSONException; import org.codehaus.jettison.json.JSONObject; public class ClientKeyDemoTest { public static void main(String[] args) throws CacheSecretException { final SecretCacheClient client = SecretCacheClientBuilder.newClient(); CredentialsProvider credentialsProvider = new CredentialsProvider() { @Override public void setCredentials(Credentials credentials) { } @Override public Credentials getCredentials() { try { SecretInfo secretInfo = client.getSecretInfo("<secretName>"); JSONObject jsonObject = new JSONObject(secretInfo.getSecretValue()); String accessKeyId = jsonObject.getString("AccessKeyId"); String accessKeySecret = jsonObject.getString("AccessKeySecret"); return new DefaultCredentials(accessKeyId, accessKeySecret); } catch (CacheSecretException | JSONException e) { return null; } } }; // 使用credentialsProvider初始化用戶端 ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration(); // 顯式聲明使用 V4 簽名演算法 clientBuilderConfiguration.setSignatureVersion(SignVersion.V4); // 建立OSSClient執行個體。 // 當OSSClient執行個體不再使用時,調用shutdown方法以釋放資源。 OSS ossClient = OSSClientBuilder.create() .endpoint("endpoint") .credentialsProvider(credentialsProvider) .clientConfiguration(clientBuilderConfiguration) .region("region") .build(); ossClient.shutdown(); } }
使用自訂訪問憑證
當以上憑證配置方式都不滿足要求時,可以通過實現Credential Providers介面的方式自訂憑證提供方式。需要注意,如果底層實現基於STS Token,需要提供憑證的更新支援。
import com.aliyun.oss.ClientBuilderConfiguration;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.common.auth.Credentials;
import com.aliyun.oss.common.auth.CredentialsProvider;
import com.aliyun.oss.common.auth.DefaultCredentials;
import com.aliyun.oss.common.comm.SignVersion;
public class CustomCredentialProviderDemoTest {
public static void main(String[] args) {
CredentialsProvider credentialsProvider = new CredentialsProvider(){
// 初始設定變數
String accessKeyId = null;
// 初始設定變數
String accessKeySecrect = null;
// 初始設定變數
// String token = null;
@Override
public void setCredentials(Credentials credentials) {
}
@Override
public Credentials getCredentials() {
//TODO
//自訂訪問憑證的擷取方法
// 返回長期憑證 access_key_id, access_key_secrect
return new DefaultCredentials(accessKeyId, accessKeySecrect);
// 返回 臨時憑證 access_key_id, access_key_secrect, token
// 對於臨時憑證,需要根據到期時間,重新整理憑證。
// return new DefaultCredentials(accessKeyId, accessKeySecrect, token);
}
};
// 使用credentialsProvider初始化用戶端
ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
// 顯式聲明使用 V4 簽名演算法
clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);
// 建立OSSClient執行個體。
// 當OSSClient執行個體不再使用時,調用shutdown方法以釋放資源。
OSS ossClient = OSSClientBuilder.create()
.endpoint("endpoint")
.credentialsProvider(credentialsProvider)
.clientConfiguration(clientBuilderConfiguration)
.region("region")
.build();
ossClient.shutdown();
}
}使用預設憑據鏈
初始化憑據用戶端時不傳入任何參數,Credentials工具會使用預設憑據鏈方式初始化用戶端。預設憑據的讀取邏輯請參見預設憑據鏈。
添加credentials依賴。
<!-- https://mvnrepository.com/artifact/com.aliyun/credentials-java --> <dependency> <groupId>com.aliyun</groupId> <artifactId>credentials-java</artifactId> <version>LATEST</version> </dependency>配置Credentials作為訪問憑證。
import com.aliyun.credentials.models.CredentialModel; import com.aliyun.oss.*; import com.aliyun.oss.common.auth.Credentials; import com.aliyun.oss.common.auth.CredentialsProvider; import com.aliyun.oss.common.auth.DefaultCredentials; import com.aliyun.oss.common.comm.SignVersion; public class Demo { public static void main(String[] args) { com.aliyun.credentials.Client credentialsClient = new com.aliyun.credentials.Client(); CredentialsProvider credentialsProvider = new CredentialsProvider(){ @Override public void setCredentials(Credentials credentials) { } @Override public Credentials getCredentials() { CredentialModel credential = credentialsClient.getCredential(); return new DefaultCredentials(credential.getAccessKeyId(), credential.getAccessKeySecret(), credential.getSecurityToken()); } }; ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration(); // 顯式聲明使用 V4 簽名演算法 clientBuilderConfiguration.setSignatureVersion(SignVersion.V4); // 使用credentialsProvider初始化用戶端 // 建立OSSClient執行個體。 // 當OSSClient執行個體不再使用時,調用shutdown方法以釋放資源。 OSS ossClient = OSSClientBuilder.create() .endpoint("endpoint") .credentialsProvider(credentialsProvider) .clientConfiguration(clientBuilderConfiguration) .region("region") .build(); ossClient.shutdown(); } }
常見問題
包衝突
錯誤原因
使用OSS Java SDK V1時,如出現以下類似錯誤,表明工程中存在包衝突問題。
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/http/ssl/TrustStrategy at com.aliyun.oss.OSSClient.<init>(OSSClient.java:268) at com.aliyun.oss.OSSClient.<init>(OSSClient.java:193) at com.aliyun.oss.demo.HelloOSS.main(HelloOSS.java:77) Caused by: java.lang.ClassNotFoundException: org.apache.http.ssl.TrustStrategy at java.net.URLClassLoader$1.run(URLClassLoader.java:366) at java.net.URLClassLoader$1.run(URLClassLoader.java:355) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:354) at java.lang.ClassLoader.loadClass(ClassLoader.java:425) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308) at java.lang.ClassLoader.loadClass(ClassLoader.java:358) ... 3 more或
Exception in thread "main" java.lang.NoSuchFieldError: INSTANCE at org.apache.http.impl.io.DefaultHttpRequestWriterFactory.<init>(DefaultHttpRequestWriterFactory.java:52) at org.apache.http.impl.io.DefaultHttpRequestWriterFactory.<init>(DefaultHttpRequestWriterFactory.java:56) at org.apache.http.impl.io.DefaultHttpRequestWriterFactory.<clinit>(DefaultHttpRequestWriterFactory.java:46) at org.apache.http.impl.conn.ManagedHttpClientConnectionFactory.<init>(ManagedHttpClientConnectionFactory.java:82) at org.apache.http.impl.conn.ManagedHttpClientConnectionFactory.<init>(ManagedHttpClientConnectionFactory.java:95) at org.apache.http.impl.conn.ManagedHttpClientConnectionFactory.<init>(ManagedHttpClientConnectionFactory.java:104) at org.apache.http.impl.conn.ManagedHttpClientConnectionFactory.<clinit>(ManagedHttpClientConnectionFactory.java:62) at org.apache.http.impl.conn.PoolingHttpClientConnectionManager$InternalConnectionFactory.<init>(PoolingHttpClientConnectionManager.java:572) at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.<init>(PoolingHttpClientConnectionManager.java:174) at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.<init>(PoolingHttpClientConnectionManager.java:158) at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.<init>(PoolingHttpClientConnectionManager.java:149) at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.<init>(PoolingHttpClientConnectionManager.java:125) at com.aliyun.oss.common.comm.DefaultServiceClient.createHttpClientConnectionManager(DefaultServiceClient.java:237) at com.aliyun.oss.common.comm.DefaultServiceClient.<init>(DefaultServiceClient.java:78) at com.aliyun.oss.OSSClient.<init>(OSSClient.java:268) at com.aliyun.oss.OSSClient.<init>(OSSClient.java:193) at OSSManagerImpl.upload(OSSManagerImpl.java:42) at OSSManagerImpl.main(OSSManagerImpl.java:63)錯誤原因是OSS Java SDK V1使用Apache HttpClient 4.4.1版本,而工程使用了與此版本衝突的Apache HttpClient或commons-httpclient jar包。在工程目錄下執行
mvn dependency:tree命令可查看工程使用的jar包及版本。如下圖所示,工程使用了與標準版本衝突的Apache HttpClient 4.3版本:
解決方案
包衝突有以下兩種解決方案:
使用統一版本:如果工程使用與Apache HttpClient 4.4.1衝突的版本,統一使用4.4.1版本,並在pom.xml中刪除其它版本的Apache HttpClient依賴。如果工程使用了commons-httpclient,同樣可能存在衝突,需刪除commons-httpclient依賴。
解決依賴衝突:如果工程依賴多個第三方包,而第三方包又依賴不同版本的Apache HttpClient,工程將出現依賴衝突,使用exclusion標籤解除衝突。詳細資料請參見Maven Guides。
OSS Java SDK V1依賴以下版本的包,衝突解決辦法與HttpClient類似:

缺少包
錯誤原因
使用OSS Java SDK V1時,如出現以下類似錯誤,表明工程中缺少編譯或運行OSS Java SDK V1所必需的包。
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/http/auth/Credentials at com.aliyun.oss.OSSClient.<init>(OSSClient.java:268) at com.aliyun.oss.OSSClient.<init>(OSSClient.java:193) at com.aliyun.oss.demo.HelloOSS.main(HelloOSS.java:76) Caused by: java.lang.ClassNotFoundException: org.apache.http.auth.Credentials at java.net.URLClassLoader$1.run(URLClassLoader.java:366) at java.net.URLClassLoader$1.run(URLClassLoader.java:355) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:354) at java.lang.ClassLoader.loadClass(ClassLoader.java:425) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308) at java.lang.ClassLoader.loadClass(ClassLoader.java:358) ... 3 more或
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/http/protocol/HttpContext at com.aliyun.oss.OSSClient.<init>(OSSClient.java:268) at com.aliyun.oss.OSSClient.<init>(OSSClient.java:193) at com.aliyun.oss.demo.HelloOSS.main(HelloOSS.java:76) Caused by: java.lang.ClassNotFoundException: org.apache.http.protocol.HttpContext at java.net.URLClassLoader$1.run(URLClassLoader.java:366) at java.net.URLClassLoader$1.run(URLClassLoader.java:355) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:354) at java.lang.ClassLoader.loadClass(ClassLoader.java:425) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308) at java.lang.ClassLoader.loadClass(ClassLoader.java:358) ... 3 more或
Exception in thread "main" java.lang.NoClassDefFoundError: org/jdom/input/SAXBuilder at com.aliyun.oss.internal.ResponseParsers.getXmlRootElement(ResponseParsers.java:645) at … … at com.aliyun.oss.OSSClient.doesBucketExist(OSSClient.java:471) at com.aliyun.oss.OSSClient.doesBucketExist(OSSClient.java:465) at com.aliyun.oss.demo.HelloOSS.main(HelloOSS.java:82) Caused by: java.lang.ClassNotFoundException: org.jdom.input.SAXBuilder at java.net.URLClassLoader$1.run(URLClassLoader.java:366) at java.net.URLClassLoader$1.run(URLClassLoader.java:355) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:354) at java.lang.ClassLoader.loadClass(ClassLoader.java:425) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308) at java.lang.ClassLoader.loadClass(ClassLoader.java:358) ... 11 moreOSS Java SDK V1依賴以下包:
aliyun-sdk-oss-2.2.1.jar
hamcrest-core-1.1.jar
jdom-1.1.jar
commons-codec-1.9.jar
httpclient-4.4.1.jar
commons-logging-1.2.jar
httpcore-4.4.1.jar
log4j-1.2.15.jar
其中log4j-1.2.15.jar為可選依賴,僅在需要日誌功能時加入,其它包均為必需依賴。
解決方案
在工程中加入OSS Java SDK V1依賴的包,具體方法如下:
Eclipse專案:請參見安裝 SDK。
Ant專案:將OSS Java SDK V1依賴的包放入工程的lib目錄中。
直接編譯:使用
-classpath或-cp命令指定OSS Java SDK V1依賴的包路徑,或將依賴包放入classpath路徑下。
連線逾時
錯誤原因
運行OSS Java SDK V1程式時出現以下類似錯誤,可能原因為Endpoint配置錯誤或網路連接異常。
com.aliyun.oss.ClientException: SocketException at com.aliyun.oss.common.utils.ExceptionFactory.createNetworkException(ExceptionFactory.java:71) at com.aliyun.oss.common.comm.DefaultServiceClient.sendRequestCore(DefaultServiceClient.java:116) at com.aliyun.oss.common.comm.ServiceClient.sendRequestImpl(ServiceClient.java:121) at com.aliyun.oss.common.comm.ServiceClient.sendRequest(ServiceClient.java:67) at com.aliyun.oss.internal.OSSOperation.send(OSSOperation.java:92) at com.aliyun.oss.internal.OSSOperation.doOperation(OSSOperation.java:140) at com.aliyun.oss.internal.OSSOperation.doOperation(OSSOperation.java:111) at com.aliyun.oss.internal.OSSBucketOperation.getBucketInfo(OSSBucketOperation.java:1152) at com.aliyun.oss.OSSClient.getBucketInfo(OSSClient.java:1220) at com.aliyun.oss.OSSClient.getBucketInfo(OSSClient.java:1214) at com.aliyun.oss.demo.HelloOSS.main(HelloOSS.java:94) Caused by: org.apache.http.conn.HttpHostConnectException: Connect to oss-test.oss-cn-hangzhou-internal.aliyuncs.com:80 [oss-test.oss-cn-hangzhou-internal.aliyuncs.com/10.84.135.99] failed: Connection timed out: connect at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:151) at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:353) at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:380) at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:236) at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:184) at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110) at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184) at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82) at com.aliyun.oss.common.comm.DefaultServiceClient.sendRequestCore(DefaultServiceClient.java:113) ... 9 more解決方案
可以使用ossutil工具快速定位錯誤原因並解決問題。
報錯SignatureDoesNotMatch
錯誤原因1:AccessKey資訊不一致
AccessKey ID和AccessKey Secret不一致。擷取AccessKey ID和AccessKey Secret的操作步驟請參見建立AccessKey。
錯誤原因2:簽名URL使用不正確
簽名URL使用錯誤樣本如下:
GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, object); request.setExpiration( new Date(new Date().getTime() + 3600 * 1000)); request.addUserMetadata("author"); URL url = ossClient.generatePresignedUrl(request); Map<String, String> header = new HashMap<String, String>(); header.put("author"); ossClient.putObject(url, new ByteArrayInputStream("Hello OSS".getBytes()), -1, header);未指定Method參數時,預設使用GET方法,但以上為PutObject請求,應指定Method參數並設定為PUT方法。
通過PutObject發送請求時,請求Header中的自訂中繼資料必須以
x-oss-meta-為首碼。以上樣本中的自訂中繼資料應改為x-oss-meta-author。解決方案:
指定Method參數,並修改Header首碼:
request.addUserMetadata("author"); request.setMethod(HttpMethod.PUT); URL url = ossClient.generatePresignedUrl(request); Map<String, String> header = new HashMap<String, String>(); header.put("x-oss-meta-" + "author"); ossClient.putObject(url, new ByteArrayInputStream("Hello OSS".getBytes()), -1, header);錯誤原因3:HttpClient版本相容性問題
使用低於3.7.0版本的OSS SDK,同時專案中引入了4.5.9及以上版本的HttpClient。
上傳的檔案名稱中包含
+字元,4.5.9版本的HttpClient不會對+進行URLEncode編碼,導致用戶端與服務端計算的簽名不一致。

解決方案:
OSS SDK升級至3.11.1及以上版本,以相容4.5.9版本的HttpClient。
移除多餘的HttpClient依賴。引入OSS SDK時會自動引入HttpClient依賴,如果第三方庫另外引入了HttpClient,請參見包衝突解決方案。
錯誤原因4:HttpClient字元集相容性問題
HttpClient 4.5.10版本不支援Header中包含ISO/9959-1標準以外的字元,但在專案中引入了4.5.10以上的httpclient,並在請求Header中包含了ISO/9959-1標準以外的字元,例如
x-oss-meta-開頭的自訂中繼資料中傳入了中文字元。
解決方案:
參見包衝突解決方案,移除衝突的HttpClient版本。
在請求Header中僅傳入符合ISO/9959-1標準的字元。
報異常“Failed to parse the response result”

錯誤原因
用戶端某些特殊的軟體攔截了HTTP請求,或者公網路由劫持了HTTP請求。
在Java 9及以上的版本中使用OSS Java SDK V1,且未在pom.xml檔案中添加JAXB相關依賴。
解決方案
切換為HTTPS請求。
添加JAXB相關依賴。操作步驟,請參見安裝 SDK。
org.apache.http.NoHttpResponseException: The target server failed to respond
錯誤原因
運行OSS Java SDK V1程式時,出現以下類似錯誤:

使用到期串連會導致上述錯誤,該錯誤僅在Java SDK 2.1.2之前的版本出現。
解決方案
升級OSS Java SDK V1至2.1.2及以上版本。
JVM中存在大量org.apache.http.impl.conn.PoolingHttpClientConnectionManager執行個體
錯誤原因
ossClient未正確關閉。
解決方案
主動關閉已執行完畢的ossClient或使用單例模式。
調用OSS Java SDK V1不響應
錯誤原因
調用OSS Java SDK V1無響應。通過
jstack -l pid命令查看堆棧,問題出現在以下位置:"main" prio=6 tid=0x000000000291e000 nid=0xc40 waiting on condition [0x0000000002dae000] java.lang.Thread.State: WAITING (parking) at sun.misc.Unsafe.park(Native Method) - parking to wait for <0x00000007d85697f8> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject) at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186) at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2043) at org.apache.http.pool.PoolEntryFuture.await(PoolEntryFuture.java:138) at org.apache.http.pool.AbstractConnPool.getPoolEntryBlocking(AbstractConnPool.java:306) at org.apache.http.pool.AbstractConnPool.access$000(AbstractConnPool.java:64) at org.apache.http.pool.AbstractConnPool$2.getPoolEntry(AbstractConnPool.java:192) at org.apache.http.pool.AbstractConnPool$2.getPoolEntry(AbstractConnPool.java:185) at org.apache.http.pool.PoolEntryFuture.get(PoolEntryFuture.java:107) at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.leaseConnection(PoolingHttpClientConnectionManager.java:276) at org.apache.http.impl.conn.PoolingHttpClientConnectionManager$1.get(PoolingHttpClientConnectionManager.java:263) at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:190) at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:184) at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110) at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184) at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82) at com.aliyun.oss.common.comm.DefaultServiceClient.sendRequestCore(DefaultServiceClient.java:113) at com.aliyun.oss.common.comm.ServiceClient.sendRequestImpl(ServiceClient.java:123) at com.aliyun.oss.common.comm.ServiceClient.sendRequest(ServiceClient.java:68) at com.aliyun.oss.internal.OSSOperation.send(OSSOperation.java:94) at com.aliyun.oss.internal.OSSOperation.doOperation(OSSOperation.java:146) at com.aliyun.oss.internal.OSSOperation.doOperation(OSSOperation.java:113) at com.aliyun.oss.internal.OSSObjectOperation.getObject(OSSObjectOperation.java:229) at com.aliyun.oss.OSSClient.getObject(OSSClient.java:629) at com.aliyun.oss.OSSClient.getObject(OSSClient.java:617) at samples.HelloOSS.main(HelloOSS.java:49)原因為串連池中串連泄漏,可能是使用ossObject後未正確關閉。
解決方案
檢查程式,確保沒有串連泄漏。正確關閉方法如下:
// 讀取檔案 OSSObject ossObject = ossClient.getObject(bucketName, objectName); // OSS操作 // 關閉ossObject ossObject.close();問題排查的具體步驟請參見OSS Java SDK V1不響應問題排查。
串連關閉
錯誤原因
使用ossClient.getObject時,如出現以下類似錯誤:
Exception in thread "main" org.apache.http.ConnectionClosedException: Premature end of Content-Length delimited message body (expected: 11990526; received: 202880) at org.apache.http.impl.io.ContentLengthInputStream.read(ContentLengthInputStream.java:180) at org.apache.http.impl.io.ContentLengthInputStream.read(ContentLengthInputStream.java:200) at org.apache.http.impl.io.ContentLengthInputStream.close(ContentLengthInputStream.java:103) at org.apache.http.impl.execchain.ResponseEntityProxy.streamClosed(ResponseEntityProxy.java:128) at org.apache.http.conn.EofSensorInputStream.checkClose(EofSensorInputStream.java:228) at org.apache.http.conn.EofSensorInputStream.close(EofSensorInputStream.java:174) at java.io.FilterInputStream.close(FilterInputStream.java:181) at java.io.FilterInputStream.close(FilterInputStream.java:181) at com.aliyun.oss.event.ProgressInputStream.close(ProgressInputStream.java:147) at java.io.FilterInputStream.close(FilterInputStream.java:181) at samples.HelloOSS.main(HelloOSS.java:39)原因為兩次讀取資料間隔時間超過1分鐘。OSS會關閉超過1分鐘沒有發送或接收資料的串連。
解決方案
如果每次僅讀取部分資料,且處理資料的時間不固定,建議使用指定範圍讀取,避免資料讀取時串連關閉。範圍下載完成後,串連會自動關閉。詳細資料請參見範圍下載(Java SDK)。
記憶體泄露
錯誤原因
調用OSS Java SDK V1的程式運行一段時間(根據業務量,幾小時到幾天不等)後出現記憶體泄露。推薦使用Eclipse Memory Analyzer (MAT)分析記憶體使用量情況。詳細資料請參見使用MAT進行堆轉儲檔案分析。
如果分析結果類似下圖所示(PoolingHttpClientConnectionManager佔96%的記憶體),原因為程式中可能多次執行
new OSSClient,但未調用ossClient.shutdown,造成記憶體流失。
解決方案
new OSSClient操作完成後,通過shutdown方法關閉,保證new OSSClient和ossClient.shutdown成對使用。
調用ossClient.shutdown報異常InterruptedException
錯誤原因
OSS Java SDK V1 2.3.0之前的版本在調用
ossClient.shutdown時報以下異常:java.lang.InterruptedException: sleep interrupted at java.lang.Thread.sleep(Native Method) at com.aliyun.oss.common.comm.IdleConnectionReaper.run(IdleConnectionReaper:76)原因為ossClient後台線程IdleConnectionReaper會定時關閉閑置串連。IdleConnectionReaper在Sleep時調用ossClient.shutdown,就會出現上述異常。
解決方案
使用以下代碼忽略該異常:
try { ossClient.shutdown(); } catch(Exception e) { }
請求出現異常“SDK.ServerUnreachable : Speicified endpoint or uri is not valid”

錯誤原因
使用者端STS並發請求過高。
網路到Server端逾時。
所使用的STS SDK以及SDK core版本過舊。
解決方案
使用者端STS並發請求過高,而使用者端的ECS或本地PC效能不足以承載當時的並發量,降低OSS並發數。
使用者網路到Server端出現逾時現象,可通過抓包驗證。
建議將STS SDK及SDK core升級至最新版本。
NoSuchKey

錯誤原因
源檔案不存在。
解決方案
參見404錯誤排查方法。
SocketException

錯誤原因
可能是socket在初始化階段失敗,導致請求未到達OSS。
解決方案
建議從以下幾個方面進行排查:
出現問題時是否有網路抖動。
主機的socket串連數是否佔滿。
確認出現問題時串連數是否超過SDK中設定的maxconnection,如果串連數超過maxconnection設定,也會出現socket異常。
如果以上都沒有問題,建議部署tcpdump或Wireshark抓包,問題複現後分析資料包。
使用OSS PostObject的callback沒有觸發回調
使用OSS PostObject的callback沒有觸發回調,但通過PutObject使用同樣的callback觸發了回調。一般情況下,如果JSON格式有誤或回調失敗,都會返回相應的訊息,需要分別測試Put和Post回調效果:

錯誤原因
發送請求時callback參數在file下面。

解決方案
調整callback參數與file的位置。

此時測試結果顯示商務服務器成功抓取請求。

Connection pool shut down
Caused by: java.lang.IllegalStateException: Connection pool shut down
at org.apache.http.util.Asserts.check(Asserts.java:34)
at org.apache.http.pool.AbstractConnPool.lease(AbstractConnPool.java:184)
at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.requestConnection(PoolingHttpClientConnectionManager.java:251)
at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:175)
at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:184)
at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
at com.aliyun.oss.common.comm.DefaultServiceClient.sendRequestCore(DefaultServiceClient.java:124)
at com.aliyun.oss.common.comm.ServiceClient.sendRequestImpl(ServiceClient.java:133)
... 8 more錯誤原因
調用
ossClient.shutdown()介面後,仍繼續通過ossClient發送請求。解決方案
檢查調用邏輯,確保調用
ossClient.shutdown()介面後,不再通過ossClient發送請求。
使用Java SDK的generatePresignedUrl產生的請求報錯Request has expired
錯誤原因
int類型溢出,導致2038年時間戳記問題。
超出URL設定的到期時間後發起上傳請求。
解決方案
如果是int類型溢出,建議Java SDK中到期時間長度不要超過2038年。
如果因超出URL設定的到期時間後發起上傳請求,建議設定合理的到期時間,確保到期時間大於發起請求的時間。
報錯Invalid Response或Implementation of JAXB-API has not been found on module path or classpath
錯誤原因
使用Java 9以上版本,並且未添加JAXB依賴。
解決方案
關於如何添加JAXB依賴的更多資訊,請參見安裝 SDK。
OSS Java SDK V1 中的 OSSClient 是安全執行緒的嗎?
OSSClient 具備安全執行緒特性,允許多線程訪問同一執行個體。結合業務需求,可以複用同一個OSSClient 執行個體,也可以建立多個 OSSClient 執行個體分別使用。
OSSClient 執行個體內部維護串連池。當 OSSClient 執行個體不再使用時,調用 shutdown 方法將其關閉,避免建立過多的 OSSClient 執行個體導致資源耗盡。
報錯AccessDenied Hierarchical namespace is disabled
錯誤原因
調用CreateDirectory、Rename或DeleteDirectory介面前未開啟階層命名空間。
解決方案
建立Bucket時開啟階層命名空間。具體步驟請參見建立儲存空間。
用戶端網路正常,但是通過HTTP訪問時報錯Connection reset,如何處理?
部分地區的電訊廠商可能會對OSS的網域名稱進行劫持,建議通過Endpoint的方式配置為HTTPS協議。詳細資料請參見配置用戶端。
Java 17 Cannot invoke "java.lang.reflect.Method.invoke(Object, Object[])" because "com.sun.xml.bind.v2.runtime.reflect.opt.Injector.defineClass" is null
問題原因
JAXB在Java 9中被標記為棄用並在Java 11中被刪除。
解決方案
添加以下依賴:
<dependency> <groupId>com.sun.xml.bind</groupId> <artifactId>jaxb-impl</artifactId> <version>2.3.1</version> </dependency> <dependency> <groupId>com.sun.xml.messaging.saaj</groupId> <artifactId>saaj-impl</artifactId> <version>1.5.1</version> </dependency>
Java SDK如何配置內部日誌列印?
Java SDK使用Apache Commons Logging(JCL)日誌架構進行日誌列印。JCL可以選擇多種日誌實現架構(具體參見:JCL-Configuration),比較常見的是JCL over log4j或JCL over SLF4j兩種,相關實現方式如下:
JCL over log4j:需要引入log4j的依賴(log4j 2.x有多種實現架構可選,預設為log4j-api+log4j-core),並按log4j的配置方式進行配置,具體流程參考APACHE LOG4J-API Separation。
JCL over slf4j:需要引入jcl-over-slf4j 和slf4j的依賴(slf4j也有多種實現架構可選,比如slf4j-api+logback-classic),並按照slf4j的配置方式進行配置,具體流程參考SJF4J-Bridging legacy APIs。
Apache Log4j定義了不同層級的日誌,包括OFF、FATAL、ERROR、WARN、INFO、DEBUG、TRACE和ALL。
通過配置log4j屬性選擇開啟或關閉SDK日誌:
