快速接入
接入 OSS Java SDK 的流程如下:
環境準備
要求 Java 7 及以上版本。
可以通過 java -version
命令查看 Java 版本。如果當前環境沒有 Java 或版本低於 Java 7,請下載 Java。
安裝 SDK
選擇以下任意一種方式安裝 OSS Java SDK。
建議使用最新版本的 OSS Java SDK,以確保程式碼範例正常運行。
在Maven專案中加入依賴項(推薦)
在Maven工程中使用OSS Java SDK,只需在pom.xml
中加入相應依賴即可。以在<dependencies>中加入 OSS Java SDK 3.17.4 依賴為例:
<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 3.17.4。
解壓該開發包。
將解壓後檔案夾中的檔案aliyun-sdk-oss-3.17.4.jar以及lib檔案夾下的所有檔案拷貝到您的專案中。
在Eclipse中選擇您的工程,右鍵選擇
。選中拷貝的所有JAR檔案,匯入到Libraries中。
在IntelliJ IDEA專案中匯入JAR包
下載OSS Java SDK 3.17.4 。
解壓該開發包。
將解壓後檔案夾中的檔案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)
初始化用戶端
使用地區和訪問網域名稱初始化 OSSClient,並運行測試代碼。
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 Demo {
public static void main(String[] args) throws Exception {
// 建立 ClientBuilderConfiguration 執行個體,用於配置 OSS 用戶端參數
ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
// 設定簽名演算法版本為 V4
clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);
// 設定使用 HTTPS 協議訪問 OSS,保證傳輸安全性
clientBuilderConfiguration.setProtocol(Protocol.HTTPS);
// 建立 OSS 用戶端執行個體
OSS ossClient = OSSClientBuilder.create()
// 以華東1(杭州)地區的外網訪問網域名稱為例,Endpoint填寫為oss-cn-hangzhou.aliyuncs.com
.endpoint("oss-cn-hangzhou.aliyuncs.com")
// 從環境變數中擷取訪問憑證(需提前配置 OSS_ACCESS_KEY_ID 和 OSS_ACCESS_KEY_SECRET)
.credentialsProvider(CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider())
// 設定用戶端配置
.clientConfiguration(clientBuilderConfiguration)
// 以華東1(杭州)地區為例,Region填寫為cn-hangzhou
.region("cn-hangzhou")
.build();
try {
// 列出目前使用者的所有 Bucket
List<Bucket> buckets = ossClient.listBuckets();
// 遍曆列印每個 Bucket 的名稱
for (Bucket bucket : buckets) {
System.out.println(bucket.getName());
}
} finally {
// 當OSSClient執行個體不再使用時,調用shutdown方法以釋放資源
ossClient.shutdown();
}
}
}
運行後將會看到當前帳號在所有地區下的 Bucket:
examplebucket
用戶端配置
使用 ClientConfiguration
類配置 OSSClient 的逾時時間、重試次數、Proxy 伺服器等參數。
使用自訂網域名
使用OSS預設網域名稱訪問時,可能會出現檔案禁止訪問、檔案無法預覽等問題;通過綁定自訂網域名至Bucket預設網域名稱,不僅支援瀏覽器直接預覽檔案,還可結合CDN加速分發。
ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
clientBuilderConfiguration.setSupportCname(true);// 請注意,設定true開啟CNAME選項。
OSS ossClient = new OSSClientBuilder()
// 其他配置...
.clientConfiguration(clientBuilderConfiguration)
.endpoint("https://static.example.com") //請填寫您的自訂網域名,例如https://static.example.com
.build();
逾時控制
使用 ClientConfiguration 類配置 OSSClient 逾時參數。
ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
clientBuilderConfiguration.setMaxConnections(1024) // 設定允許開啟的最大HTTP串連數。不設定時預設為1024。
.setSocketTimeout(50000) // 設定Socket層傳輸資料的逾時時間(單位:毫秒)。不設定時預設為50000毫秒。
.setConnectionTimeout(50000) // 設定建立串連的逾時時間(單位:毫秒)。不設定時預設為50000毫秒。
.setConnectionRequestTimeout(60 * 60 * 24 * 1000) // 設定從串連池中擷取串連的逾時時間(單位:毫秒)。不設定時預設無逾時限制。
.setIdleConnectionTime(60000); // 設定串連空閑逾時時間,逾時則關閉串連(單位:毫秒)。不設定時預設為60000毫秒。
OSS ossClient = new OSSClientBuilder()
// 其他配置...
.clientConfiguration(clientBuilderConfiguration)
.build();
最大錯誤重試次數
請求異常時,OSSClient 預設重試 3 次。
高並發或網路不穩定時,使用 setMaxErrorRetry
增加重試次數。這能提升請求成功率。
ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
clientBuilderConfiguration.setMaxErrorRetry(5);
OSS ossClient = new OSSClientBuilder()
// 其他配置...
.clientConfiguration(clientBuilderConfiguration)
.build();
重試策略
不建議使用setRetryStrategy
設定自訂重試策略。自訂策略可能導致不穩定行為。
請求異常時,OSSClient 根據請求類型執行重試策略:
POST 請求:預設不重試。
非 POST 請求:滿足以下條件時重試,最多3次:
ClientException
異常,錯誤碼為:ConnectionTimeout
、SocketTimeout
、ConnectionRefused
、UnknownHost
、SocketException
。OSSException
異常,錯誤碼非InvalidResponse
。HTTP 狀態代碼為 500、502 或 503。
Proxy 伺服器
企業安全性原則通常限制直接存取公網。使用 setProxyHost
配置Proxy 伺服器訪問 OSS。
ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
// 設定使用者代理程式,指HTTP的User-Agent頭,預設為aliyun-sdk-java。
clientBuilderConfiguration.setUserAgent("aliyun-sdk-java");
// 設定Proxy 伺服器IP,請將"<yourProxyHost>"替換為Proxy 伺服器的IP地址(如"196.128.xxx.xxx")。
clientBuilderConfiguration.setProxyHost("<yourProxyHost>");
// 設定Proxy 伺服器訪問連接埠,例如8080連接埠。
clientBuilderConfiguration.setProxyPort(8080);
// 設定Proxy 伺服器驗證的使用者名稱,請將"<yourProxyUserName>"替換為Proxy 伺服器的使用者名稱(如"root")。
clientBuilderConfiguration.setProxyUsername("<yourProxyUserName>");
// 設定Proxy 伺服器驗證的密碼,請將"<yourProxyPassword>"替換為該使用者的驗證密碼。
clientBuilderConfiguration.setProxyPassword("<yourProxyPassword>");
OSS ossClient = new OSSClientBuilder()
// 其他配置...
.clientConfiguration(clientBuilderConfiguration)
.build();
HTTP/HTTPS 協議
使用 setProtocol
設定通訊協定。預設使用 HTTP,生產環境建議使用 HTTPS 加密傳輸。
ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
clientBuilderConfiguration.setProtocol(Protocol.HTTPS);
OSS ossClient = new OSSClientBuilder()
// 其他配置...
.clientConfiguration(clientBuilderConfiguration)
.build();
簽名版本
阿里雲Object Storage Service的 V1 簽名將於 2025 年 3 月 1 日起逐步不再對新客戶(新的 uid )開放使用,將於 2025 年 9 月 1 日起逐步停止更新與維護且不再對新增的 Bucket 開放使用。請儘快從V1簽名升級為V4簽名,避免影響服務。
使用 setSignatureVersion
設定簽名版本。使用 V4 簽名時,必須通過 region
指定地區ID。OSS Java SDK 3.15.0 及以上版本支援 V4 簽名。
ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);
OSS ossClient = new OSSClientBuilder()
// 其他配置...
.region("cn-hangzhou")
.clientConfiguration(clientBuilderConfiguration)
.build();
使用 IP 位址
使用 IP 位址作為 Endpoint 主要用於內網訪問。通過 CEN、Express Connect、專線、VPN 等建立串連後,參考各地區 OSS內網網域名稱與VIP網段對照表配置相應的路由。
ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
// 開啟次層網域訪問OSS,預設情況下是關閉的。
// OSS Java SDK 2.1.2及之前的版本需要設定此值,
// 2.1.2及之後的版本會自動檢測到IP地址,因此不再需要設定此值。
clientBuilderConfiguration.setSLDEnabled(true);
OSS ossClient = new OSSClientBuilder()
// 其他配置...
.clientConfiguration(clientBuilderConfiguration)
.endpoint("http://10.10.10.10") // 使用IP地址訪問OSS時,建議使用HTTP協議以避免SSL認證校正問題。
.build();
CRC 校正
OSS 預設開啟 CRC 資料校正功能,保證傳輸完整性。雖然會輕微影響效能,但建議在生產環境中保持開啟。以下情境可考慮關閉 CRC 校正提升效能: 直播預覽流、IoT 裝置即時資料、低品質監控視頻等可容忍少量資料丟失的即時業務。關閉 CRC 校正前必須充分評估相關風險,進行完整測實驗證,確保重要業務資料優先保證一致性。
ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
ClientConfiguration.setCrcCheckEnabled(false);
OSS ossClient = new OSSClientBuilder()
// 其他配置...
.clientConfiguration(clientBuilderConfiguration)
.build();
訪問憑證配置
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 X/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,您可以使用RAMRoleARN初始化憑證提供者。該方式底層實現是STS Token。通過指定RAM角色的ARN(Alibabacloud Resource Name),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配置ServiceAccount的RAM許可權實現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 時,推薦採用單例模式來建立和使用 OSSClient 執行個體。
OSSClient是安全執行緒的,允許多線程訪問同一執行個體。您可以結合業務需求,採用單例模式建立並複用 OSSClient 執行個體。
OSSClient執行個體內部維持一個串連池。當OSSClient執行個體不再使用時,請調用shutdown方法將其關閉,避免建立過多的OSSClient執行個體導致資源耗盡。
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 中包含兩類異常:ClientException 和 OSSException,它們均繼承自 RuntimeException,在使用過程中可根據具體業務情境進行捕獲和處理。
用戶端異常(ClientException)
指用戶端在構建請求、發送請求或傳輸資料過程中發生的異常。常見情境包括:
網路連接不可用,導致請求無法發送到服務端。
上傳檔案時發生 IO 異常。
請求逾時、認證驗證失敗等底層異常情況。
拋出 ClientException 表示請求未成功發送至 OSS 服務端,或在用戶端處理過程中出現錯誤。
服務端異常(OSSException)
表示 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提供豐富的範例程式碼,方便您參考或直接使用。範例程式碼包括以下內容:
樣本檔案 | 樣本內容 |
說明 PostObject的實現不依賴Java SDK。 | |
常見問題
包衝突
錯誤原因
使用OSS Java SDK時,報類似如下錯誤,說明工程中可能有包衝突。
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使用了Apache HttpClient 4.4.1,而您的工程使用了與Apache HttpClient 4.4.1衝突的Apache HttpClient或commons-httpclient jar包。要查看工程使用的jar包及版本,請在您的工程目錄下執行
mvn dependency:tree
。如下圖所示,您的工程裡使用了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依賴以下版本的包,衝突解決辦法與HttpClient類似。
缺少包
錯誤原因
使用OSS Java SDK時,報類似如下錯誤,說明您的工程中可能缺少編譯或運行OSS Java SDK所必需的包。
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 more
OSS Java SDK依賴下列包:
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依賴的包。加入方法如下:
如果您的工程在Eclipse中,請參見Java SDK使用手冊中的安裝方式二。
如果您的工程在Ant中,請把OSS Java SDK依賴的包放入工程的lib目錄中。
如果您直接使用.javac或.java檔案,請使用
-classpath
或-cp
命令指定OSS Java SDK依賴的包路徑,或把OSS Java SDK依賴的包放入classpath路徑下。
連線逾時
錯誤原因
運行OSS Java SDK程式時報如下類似錯誤,可能原因是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 ID和AccessKey Secret不一致。
有關擷取AccessKey ID和AccessKey Secret的操作步驟,請參見建立AccessKey。
錯誤原因2
簽名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
使用了低於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 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 11上使用OSS Java SDK,且未在pom.xml檔案中添加JAXB相關依賴。
解決方案
切換為HTTPS請求。
添加JAXB相關依賴。操作步驟,請參見安裝SDK。
org.apache.http.NoHttpResponseException: The target server failed to respond
錯誤原因
運行OSS Java SDK程式時,報類似如下錯誤:
使用到期的串連會導致上述錯誤,該錯誤僅在Java SDK 2.1.2之前的版本出現。
解決方案
請升級OSS Java SDK到2.1.2及以後版本。
JVM中存在大量org.apache.http.impl.conn.PoolingHttpClientConnectionManager執行個體
錯誤原因
ossClient沒有關閉導致。
解決方案
主動關閉已執行完畢的ossClient或使用單例模式。
調用OSS Java SDK不響應
錯誤原因
調用OSS Java SDK不響應。通過
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不響應問題排查。
串連關閉
錯誤原因
如果您在使用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分鐘沒有發送或接收資料的串連。
解決方案
如果您每次僅讀取部分資料,且處理資料的時間不固定,建議使用指定範圍讀取,避免資料讀取時串連關閉。當範圍下載完成後,串連將關閉。更多資訊,請參見範圍下載。
記憶體泄露
錯誤原因
調用OSS Java SDK的程式,運行一段時間(根據業務量,幾小時到幾天不等)後記憶體泄露。 推薦使用Eclipse Memory Analyzer (MAT)分析記憶體使用量情況。更多資訊,請參見使用MAT進行堆轉儲檔案分析。
如果分析結果類似下圖所示(PoolingHttpClientConnectionManager佔96%的記憶體),原因是程式中可能多次執行new OSSClient,但是沒有調用ossClient.shutdown,造成記憶體流失。
解決方案
new OSSClient操作完成後,請通過shutdown進行關閉,保證new OSSClient和ossClient.shutdown成對使用。
調用ossClient.shutdown報異常InterruptedException
錯誤原因
OSS Java SDK 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在init階段就失敗了,導致請求沒有到達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 中的 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日誌: