快速接入
接入 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 的超时时间、重试次数、代理服务器等参数。
使用自定义域名
使用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。
代理服务器
企业安全策略通常限制直接访问公网。使用 setProxyHost
配置代理服务器访问 OSS。
ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
// 设置用户代理,指HTTP的User-Agent头,默认为aliyun-sdk-java。
clientBuilderConfiguration.setUserAgent("aliyun-sdk-java");
// 设置代理服务器IP,请将"<yourProxyHost>"替换为代理服务器的IP地址(如"196.128.xxx.xxx")。
clientBuilderConfiguration.setProxyHost("<yourProxyHost>");
// 设置代理服务器访问端口,例如8080端口。
clientBuilderConfiguration.setProxyPort(8080);
// 设置代理服务器验证的用户名,请将"<yourProxyUserName>"替换为代理服务器的用户名(如"root")。
clientBuilderConfiguration.setProxyUsername("<yourProxyUserName>");
// 设置代理服务器验证的密码,请将"<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();
签名版本
阿里云对象存储的 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、高速通道、专线、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实例、容器服务Kubernetes版的Worker节点中,建议您使用ECSRAMRole初始化凭证提供者。该方式底层实现是STS Token。ECSRAMRole允许您将一个角色关联到ECS实例、ECI实例或容器服务 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
在容器服务Kubernetes版中设置了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(); } }
使用函数计算上下文中的Credentials
如果您的应用程序的函数部署运行在函数计算中,您可以使用函数计算上下文中的Credentials初始化凭证提供者。该方式底层实现是STS Token。函数计算根据函数配置的角色,通过扮演服务角色,而获取一个STS Token,然后通过上下文中的参数Credentials将STS Token传递给您的应用程序。该STS Token的有效期为36小时,且不支持修改。函数的最大执行时间为24小时,因此,执行函数过程中,STS Token不会过期,您无需考虑刷新问题。该方式无需您提供一个AK或STS Token,消除了手动维护AK或STS Token的风险。如何授予函数计算访问OSS的权限,请参见使用函数角色授予函数计算访问其他云服务的权限。
添加函数计算上下文依赖。
<!-- 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>
使用函数计算上下文中的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后,密钥管理服务(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日志: