快速接入
通过以下步骤快速接入 OSS Java SDK V1:
准备环境
安装 Java 7 及以上版本。通过 java -version 命令查看 Java 版本,如当前环境没有 Java 或版本低于 Java 7,请下载Java。
安装 SDK
根据开发环境选择合适的安装方式。建议使用最新版本的 OSS Java SDK V1,确保代码示例正常运行。
以安装3.17.4版本的OSS Java SDK V1为例进行介绍。
添加Maven依赖(推荐)
在Maven项目中使用OSS Java SDK V1,只需在pom.xml中加入相应依赖。
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.17.4</version>
</dependency>如使用Java 9及以上版本,需要添加以下JAXB相关依赖。
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
<!-- no more than 2.3.3-->
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.3.3</version>
</dependency>在Eclipse项目中导入JAR包
下载OSS Java SDK V1。
解压开发包。
将解压后文件夹中的文件aliyun-sdk-oss-3.17.4.jar以及lib文件夹下的所有文件拷贝到项目中。
在Eclipse中选择工程,右键选择。
选中拷贝的所有JAR文件,导入到Libraries中。
在IntelliJ IDEA项目中导入JAR包
下载OSS Java SDK V1 。
解压开发包。
将解压后文件夹中的文件aliyun-sdk-oss-3.17.4.jar以及lib文件夹下的所有JAR文件拷贝到项目中。
在IntelliJ IDEA中选择工程,右键选择 。
选中拷贝的所有JAR文件,导入到External Libraries中。
配置访问凭证
使用 RAM 用户的 AccessKey 配置访问凭证。
在 RAM 控制台,创建使用永久 AccessKey 访问的 RAM 用户,保存 AccessKey,然后为该用户授予
AliyunOSSFullAccess权限。使用 RAM 用户的 AccessKey 配置环境变量。
Linux
在命令行界面执行以下命令,将环境变量设置追加到
~/.bashrc文件中。echo "export OSS_ACCESS_KEY_ID='YOUR_ACCESS_KEY_ID'" >> ~/.bashrc echo "export OSS_ACCESS_KEY_SECRET='YOUR_ACCESS_KEY_SECRET'" >> ~/.bashrc执行以下命令使变更生效。
source ~/.bashrc执行以下命令检查环境变量是否生效。
echo $OSS_ACCESS_KEY_ID echo $OSS_ACCESS_KEY_SECRET
macOS
在终端中执行以下命令,查看默认Shell类型。
echo $SHELL根据默认Shell类型进行操作。
Zsh
执行以下命令,将环境变量设置追加到
~/.zshrc文件中。echo "export OSS_ACCESS_KEY_ID='YOUR_ACCESS_KEY_ID'" >> ~/.zshrc echo "export OSS_ACCESS_KEY_SECRET='YOUR_ACCESS_KEY_SECRET'" >> ~/.zshrc执行以下命令使变更生效。
source ~/.zshrc执行以下命令检查环境变量是否生效。
echo $OSS_ACCESS_KEY_ID echo $OSS_ACCESS_KEY_SECRET
Bash
执行以下命令,将环境变量设置追加到
~/.bash_profile文件中。echo "export OSS_ACCESS_KEY_ID='YOUR_ACCESS_KEY_ID'" >> ~/.bash_profile echo "export OSS_ACCESS_KEY_SECRET='YOUR_ACCESS_KEY_SECRET'" >> ~/.bash_profile执行以下命令使变更生效。
source ~/.bash_profile执行以下命令检查环境变量是否生效。
echo $OSS_ACCESS_KEY_ID echo $OSS_ACCESS_KEY_SECRET
Windows
CMD
在CMD中运行以下命令。
setx OSS_ACCESS_KEY_ID "YOUR_ACCESS_KEY_ID" setx OSS_ACCESS_KEY_SECRET "YOUR_ACCESS_KEY_SECRET"运行以下命令,检查环境变量是否生效。
echo %OSS_ACCESS_KEY_ID% echo %OSS_ACCESS_KEY_SECRET%
PowerShell
在PowerShell中运行以下命令。
[Environment]::SetEnvironmentVariable("OSS_ACCESS_KEY_ID", "YOUR_ACCESS_KEY_ID", [EnvironmentVariableTarget]::User) [Environment]::SetEnvironmentVariable("OSS_ACCESS_KEY_SECRET", "YOUR_ACCESS_KEY_SECRET", [EnvironmentVariableTarget]::User)运行以下命令,检查环境变量是否生效。
[Environment]::GetEnvironmentVariable("OSS_ACCESS_KEY_ID", [EnvironmentVariableTarget]::User) [Environment]::GetEnvironmentVariable("OSS_ACCESS_KEY_SECRET", [EnvironmentVariableTarget]::User)
初始化客户端
以下示例代码使用华东1(杭州)地域的外网访问域名初始化客户端,并列举该地域下的Bucket列表作为验证。完整的地域和Endpoint列表请参见地域和Endpoint。
import com.aliyun.oss.*;
import com.aliyun.oss.common.auth.*;
import com.aliyun.oss.common.comm.SignVersion;
import com.aliyun.oss.model.Bucket;
import java.util.List;
/**
* OSS SDK 快速接入示例
* 演示如何初始化 OSS 客户端并列出所有 Bucket
*/
public class Test {
public static void main(String[] args) {
// 从环境变量获取访问凭证
String accessKeyId = System.getenv("OSS_ACCESS_KEY_ID");
String accessKeySecret = System.getenv("OSS_ACCESS_KEY_SECRET");
// 设置OSS地域和Endpoint
String region = "cn-hangzhou";
String endpoint = "oss-cn-hangzhou.aliyuncs.com";
// 创建凭证提供者
DefaultCredentialProvider provider = new DefaultCredentialProvider(accessKeyId, accessKeySecret);
// 配置客户端参数
ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
// 显式声明使用V4签名算法
clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);
// 初始化OSS客户端
OSS ossClient = OSSClientBuilder.create()
.credentialsProvider(provider)
.clientConfiguration(clientBuilderConfiguration)
.region(region)
.endpoint(endpoint)
.build();
// 列出当前用户的所有Bucket
List<Bucket> buckets = ossClient.listBuckets();
System.out.println("成功连接到OSS服务,当前账号下的Bucket列表:");
if (buckets.isEmpty()) {
System.out.println("当前账号下暂无Bucket");
} else {
for (Bucket bucket : buckets) {
System.out.println("- " + bucket.getName());
}
}
// 释放资源
ossClient.shutdown();
System.out.println("OSS客户端已关闭");
}
}运行后将显示当前账号在所有地域下的 Bucket 列表:
成功连接到OSS服务,当前账号下的Bucket列表:
- example-bucket
OSS客户端已关闭客户端配置
使用 ClientConfiguration 类配置 OSSClient 的超时时间、重试次数、代理服务器等参数。
使用自定义域名
使用OSS默认域名访问时,由于OSS的安全策略限制,可能会出现文件禁止访问、无法直接预览等问题。通过绑定自定义域名访问OSS,不仅可以绕过这些访问限制,实现文件的直接预览,还能结合CDN服务实现全球加速分发,提升用户访问体验。
ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
// 开启CNAME选项以支持自定义域名访问
clientBuilderConfiguration.setSupportCname(true);
OSS ossClient = new OSSClientBuilder()
// 其他配置...
.clientConfiguration(clientBuilderConfiguration)
// 使用您的自定义域名作为Endpoint,例如 https://static.example.com
.endpoint("https://static.example.com")
.build();使用内网域名
当应用程序部署在阿里云ECS、容器服务或其他阿里云产品上时,使用OSS内网域名可以享受免费的内网流量传输,同时获得更快的传输速度和更高的网络稳定性。内网访问适用于大文件上传、批量数据处理和高频访问场景,有效降低成本并提升性能。完整的地域和内网Endpoint列表请参见地域和Endpoint。
ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
OSS ossClient = new OSSClientBuilder()
// 其他配置...
.clientConfiguration(clientBuilderConfiguration)
// 使用内网域名,以华东1(杭州)为例,其他地域请按实际情况填写
.endpoint("oss-cn-hangzhou-internal.aliyuncs.com")
.build();超时控制
根据业务场景合理配置超时参数。对于大文件传输或网络环境不稳定的场景,建议适当增加超时时间;对于高并发轻量级操作,可以设置较短的超时时间以快速释放资源。
ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
// 设置允许打开的最大HTTP连接数,默认为1024
clientBuilderConfiguration.setMaxConnections(1024)
// 设置Socket层传输数据的超时时间(单位:毫秒),默认为50000毫秒
.setSocketTimeout(50000)
// 设置建立连接的超时时间(单位:毫秒),默认为50000毫秒
.setConnectionTimeout(50000)
// 设置从连接池中获取连接的超时时间(单位:毫秒),默认无超时限制
.setConnectionRequestTimeout(60 * 60 * 24 * 1000)
// 设置连接空闲超时时间,超时则关闭连接(单位:毫秒),默认为60000毫秒
.setIdleConnectionTime(60000);
OSS ossClient = new OSSClientBuilder()
// 其他配置...
.clientConfiguration(clientBuilderConfiguration)
.build();最大错误重试次数
OSS客户端默认重试3次以提升请求成功率。在高并发或网络不稳定环境下,适当使用 setMaxErrorRetry 增加重试次数可以显著改善服务可用性,建议根据业务对延迟的容忍度和网络环境质量来调整重试次数。
ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
// 设置请求失败后的最大重试次数,根据网络环境和业务需求调整
clientBuilderConfiguration.setMaxErrorRetry(5);
OSS ossClient = new OSSClientBuilder()
// 其他配置...
.clientConfiguration(clientBuilderConfiguration)
.build();重试策略
不建议使用setRetryStrategy设置自定义重试策略,因为自定义策略可能导致不可预期的行为,影响服务稳定性。OSS客户端针对不同请求类型采用经过验证的重试策略:
POST 请求:默认不重试,避免重复提交导致的数据不一致。
非 POST 请求:在满足以下条件时自动重试,最多重试3次。
ClientException异常,错误码为:ConnectionTimeout、SocketTimeout、ConnectionRefused、UnknownHost、SocketException。OSSException异常,错误码非InvalidResponse。HTTP 状态码为 500、502 或 503 的服务端临时错误。
代理服务器
企业网络环境通常通过代理服务器访问外部资源以确保安全性。配置代理服务器后,OSS客户端将通过指定的代理转发所有HTTP请求,实现安全的OSS服务访问。
ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
// 设置用户代理,指定HTTP的User-Agent头,默认为aliyun-sdk-java
clientBuilderConfiguration.setUserAgent("aliyun-sdk-java");
// 设置代理服务器IP地址,请将""替换为实际的代理服务器IP(如"196.128.xxx.xxx")
clientBuilderConfiguration.setProxyHost("");
// 设置代理服务器访问端口,例如8080端口
clientBuilderConfiguration.setProxyPort(8080);
// 设置代理服务器验证的用户名,请将""替换为实际的用户名(如"admin")
clientBuilderConfiguration.setProxyUsername("");
// 设置代理服务器验证的密码,请将""替换为对应的验证密码
clientBuilderConfiguration.setProxyPassword("");
OSS ossClient = new OSSClientBuilder()
// 其他配置...
.clientConfiguration(clientBuilderConfiguration)
.build();HTTP/HTTPS 协议
通过 setProtocol 设置客户端与OSS服务端的通信协议。默认使用HTTP协议,生产环境强烈建议使用HTTPS协议以确保数据传输安全,防止中间人攻击和数据泄露。
ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
// 设置通信协议为HTTPS,确保数据传输安全
clientBuilderConfiguration.setProtocol(Protocol.HTTPS);
OSS ossClient = new OSSClientBuilder()
// 其他配置...
.clientConfiguration(clientBuilderConfiguration)
.build();签名版本
阿里云对象存储 V1 签名将按以下时间表停止使用,建议尽快升级至 V4 签名,确保服务不受影响。
自 2025 年 3 月 1 日起,新注册用户无法使用 V1 签名。
自 2025 年 9 月 1 日起,逐步停止 V1 签名的更新维护,且新创建的 Bucket 无法使用 V1 签名。
使用 setSignatureVersion 配置签名算法版本。使用 V4 签名时,必须通过 region 参数指定正确的地域ID。V4签名算法提供更高的安全性,OSS Java SDK V1 3.15.0 及以上版本支持 V4 签名。
ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
// 设置签名算法版本为V4,提供更高的安全性
clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);
OSS ossClient = new OSSClientBuilder()
// 其他配置...
// 使用V4签名时必须指定地域ID
.region("cn-hangzhou")
.clientConfiguration(clientBuilderConfiguration)
.build();使用 IP 地址
使用IP地址作为Endpoint主要用于内网访问和特殊网络环境场景。通过CEN、高速通道、专线、VPN等方式建立网络连接后,可以使用IP地址直接访问OSS,绕过DNS解析过程提升访问效率,具体路由配置可参考OSS内网域名与VIP网段对照表。
ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
// 开启二级域名访问OSS,默认情况下是关闭的
// OSS Java SDK V1 2.1.2及之前的版本需要设置此值
// 2.1.2及之后的版本会自动检测到IP地址,因此不再需要设置此值
clientBuilderConfiguration.setSLDEnabled(true);
OSS ossClient = new OSSClientBuilder()
// 其他配置...
.clientConfiguration(clientBuilderConfiguration)
// 使用IP地址访问OSS时,建议使用HTTP协议以避免SSL证书校验问题
.endpoint("http://10.10.10.10")
.build();CRC 校验
OSS默认开启CRC数据校验功能以保证数据传输完整性,虽然会略微增加传输时间,但建议在生产环境中保持开启以确保数据一致性。以下特定场景可考虑关闭CRC校验以提升传输性能:直播预览流、IoT设备实时数据、低质量监控视频等可容忍少量数据丢失的实时业务,或在高可靠内网环境下的批量数据传输。关闭CRC校验前,请充分评估数据一致性风险并进行完整的测试验证。
ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
// 关闭CRC数据校验功能,请谨慎使用并充分评估风险
clientBuilderConfiguration.setCrcCheckEnabled(false);
OSS ossClient = new OSSClientBuilder()
// 其他配置...
.clientConfiguration(clientBuilderConfiguration)
.build();单例模式
OSS Java SDK V1 推荐采用单例模式来创建和使用 OSSClient 实例。
OSSClient 具备线程安全特性,支持多线程并发访问同一实例。结合业务需求,采用单例模式创建并复用 OSSClient 实例,可以避免频繁创建销毁实例的开销。
OSSClient 实例内部维护连接池,当确定 OSSClient 实例不再使用时,调用 shutdown 方法关闭实例,防止创建过多实例导致系统资源耗尽。
import com.aliyun.oss.ClientBuilderConfiguration;
import com.aliyun.oss.OSS;
import com.aliyun.oss.*;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.common.auth.CredentialsProvider;
import com.aliyun.oss.common.auth.CredentialsProviderFactory;
import com.aliyun.oss.common.comm.SignVersion;
import com.aliyun.oss.internal.OSSHeaders;
import com.aliyun.oss.model.*;
import java.io.ByteArrayInputStream;
public class OssClientSingleton {
private OssClientSingleton() {}
// 静态内部类实现单例(线程安全)
private static class SingletonHolder {
private static final OSS INSTANCE = create();
private static OSS create() {
try {
// Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。
String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
// 填写Bucket所在地域。以华东1(杭州)为例,Region填写为cn-hangzhou。
String region = "cn-hangzhou";
ClientBuilderConfiguration config = new ClientBuilderConfiguration();
// 显式声明使用 V4 签名算法
config.setSignatureVersion(SignVersion.V4);
//从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
CredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
// 构建OSS客户端
return OSSClientBuilder.create()
.endpoint(endpoint)
.credentialsProvider(credentialsProvider)
.clientConfiguration(config)
.region(region)
.build();
} catch (Exception e) {
throw new RuntimeException("OSS客户端初始化失败", e);
}
}
}
// 获取单例实例
public static OSS getInstance() {
return SingletonHolder.INSTANCE;
}
// 主函数测试PutObject操作
public static void main(String[] args) {
// 获取单例OSS客户端
OSS ossClient = OssClientSingleton.getInstance();
// 填写Bucket名称,例如examplebucket。
String bucketName = "examplebucket";
// 填写不包含Bucket名称在内的Object完整路径,例如testfolder/exampleobject.txt。
String objectKey = "testfolder/exampleobject.txt";
try {
// 填写字符串。
String content = "Hello OSS";
// 创建PutObjectRequest对象。
PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectKey, new ByteArrayInputStream(content.getBytes()));
// 如果需要上传时设置存储类型和访问权限,请参考以下示例代码。
ObjectMetadata metadata = new ObjectMetadata();
metadata.setHeader(OSSHeaders.OSS_STORAGE_CLASS, StorageClass.Standard.toString());
metadata.setObjectAcl(CannedAccessControlList.Private);
putObjectRequest.setMetadata(metadata);
// 上传字符串。
PutObjectResult result = ossClient.putObject(putObjectRequest);
// 打印上传结果。
System.out.println("文件上传成功!");
System.out.println("ETag: " + result.getETag());
System.out.println("请求ID: " + result.getRequestId());
} catch (OSSException oe) {
System.out.println("Caught an OSSException, which means your request made it to OSS, "
+ "but was rejected with an error response for some reason.");
System.out.println("Error Message:" + oe.getErrorMessage());
System.out.println("Error Code:" + oe.getErrorCode());
System.out.println("Request ID:" + oe.getRequestId());
System.out.println("Host ID:" + oe.getHostId());
} catch (ClientException ce) {
System.out.println("Caught an ClientException, which means the client encountered "
+ "a serious internal problem while trying to communicate with OSS, "
+ "such as not being able to access the network.");
System.out.println("Error Message:" + ce.getMessage());
} finally {
// 在单例模式下,不建议在每次操作后关闭client(保持连接复用),避免影响后续使用。
// 在明确OSSClient实例不再使用时(例如应用程序退出前),调用一次shutdown方法以释放资源。
// ossClient.shutdown();
}
}
}
异常处理
OSS Java SDK V1包含两类异常:ClientException和OSSException,均继承自RuntimeException。
客户端异常(ClientException)
客户端异常指在构建请求、发送请求或传输数据过程中发生的异常。常见场景包括:
网络连接不可用,导致请求无法发送到服务端。
上传文件时发生 IO 异常。
请求超时、证书验证失败等底层网络异常。
抛出ClientException表示请求未成功发送至OSS服务端,或在客户端处理过程中出现错误,通常需要检查网络连接状态、客户端配置或重试机制。
服务端异常(OSSException)
服务端异常表示OSS服务端返回的异常信息,即请求已成功发送并被服务端接收,但由于某些原因未能正常处理。OSS服务端异常具有以下特点:
包含详细的错误码(ErrorCode)和错误信息(ErrorMessage),便于精确定位问题。
常见错误包括签名不匹配(SignatureDoesNotMatch)、权限不足(AccessDenied)、资源不存在(NoSuchKey)等。
通过错误码进行针对性处理,可以显著提升程序的健壮性和用户体验。
在实际开发中建议对这两类异常分别进行捕获,以便更准确地判断问题来源并制定相应的处理策略。
// 创建客户端的操作...
try {
// 执行OSS操作,例如上传文件、下载文件、列举对象等
// 这里的操作可能会抛出OSS相关的异常
ossClient.putObject(...);
} catch (OSSException oe) {
// 捕获OSS服务端返回的异常
// 当请求成功到达OSS服务端,但服务端拒绝执行请求时抛出此异常
// 常见原因:权限不足、参数错误、资源不存在等
System.out.println("Caught an OSSException, which means your request made it to OSS, "
+ "but was rejected with an error response for some reason.");
// 输出详细的错误信息,便于问题定位和调试
System.out.println("Error Message: " + oe.getErrorMessage());
System.out.println("Error Code: " + oe.getErrorCode());
System.out.println("Request ID: " + oe.getRequestId());
System.out.println("Host ID: " + oe.getHostId());
} catch (ClientException ce) {
// 捕获客户端异常
// 当客户端在与OSS通信过程中遇到严重内部问题时抛出此异常
// 常见原因:网络连接问题、SSL证书问题、DNS解析失败等
System.out.println("Caught an ClientException, which means the client encountered "
+ "a serious internal problem while trying to communicate with OSS, "
+ "such as not being able to access the network.");
// 输出客户端异常的详细信息
System.out.println("Error Message: " + ce.getMessage());
} finally {
// 无论操作成功或失败,都需要释放客户端资源
// 这是最佳实践,避免资源泄漏和连接池耗尽
if (ossClient != null) {
ossClient.shutdown(); // 关闭客户端,释放网络连接等资源
}
}示例代码
OSS Java SDK V1提供丰富的示例代码,涵盖存储空间管理、文件操作、权限控制、加密传输等核心功能,便于参考或直接使用。示例代码包括以下内容:
示例文件 | 示例内容 |
说明 PostObject的实现不依赖Java SDK。 | |
访问凭证配置
OSS 支持多种凭证初始化方式,需根据认证和授权需求选择合适的初始化方式。
使用RAM用户的AK
适用于应用程序部署运行在安全、稳定且不易受外部攻击的环境中,需要长期访问OSS且无法频繁轮转凭证的场景。通过阿里云主账号或RAM用户的AK(Access Key ID、Access Key Secret)初始化凭证提供者。该方式需要手动维护AK,存在安全性风险和维护复杂度增加的风险。
阿里云账号拥有资源的全部权限,AK一旦泄露,会给系统带来巨大风险,不建议使用。推荐使用最小化授权的RAM用户的AK。
如需创建RAM用户的AK,请直接访问创建AccessKey。RAM用户的Access Key ID、Access Key Secret信息仅在创建时显示,如若遗忘请创建新的AK进行替换。
环境变量
使用RAM用户AccessKey配置环境变量。
Linux
在命令行界面执行以下命令,将环境变量设置追加到
~/.bashrc文件中。echo "export OSS_ACCESS_KEY_ID='YOUR_ACCESS_KEY_ID'" >> ~/.bashrc echo "export OSS_ACCESS_KEY_SECRET='YOUR_ACCESS_KEY_SECRET'" >> ~/.bashrc执行以下命令使变更生效。
source ~/.bashrc执行以下命令检查环境变量是否生效。
echo $OSS_ACCESS_KEY_ID echo $OSS_ACCESS_KEY_SECRET
macOS
在终端中执行以下命令,查看默认Shell类型。
echo $SHELL根据默认Shell类型进行操作。
Zsh
执行以下命令,将环境变量设置追加到
~/.zshrc文件中。echo "export OSS_ACCESS_KEY_ID='YOUR_ACCESS_KEY_ID'" >> ~/.zshrc echo "export OSS_ACCESS_KEY_SECRET='YOUR_ACCESS_KEY_SECRET'" >> ~/.zshrc执行以下命令使变更生效。
source ~/.zshrc执行以下命令检查环境变量是否生效。
echo $OSS_ACCESS_KEY_ID echo $OSS_ACCESS_KEY_SECRET
Bash
执行以下命令,将环境变量设置追加到
~/.bash_profile文件中。echo "export OSS_ACCESS_KEY_ID='YOUR_ACCESS_KEY_ID'" >> ~/.bash_profile echo "export OSS_ACCESS_KEY_SECRET='YOUR_ACCESS_KEY_SECRET'" >> ~/.bash_profile执行以下命令使变更生效。
source ~/.bash_profile执行以下命令检查环境变量是否生效。
echo $OSS_ACCESS_KEY_ID echo $OSS_ACCESS_KEY_SECRET
Windows
CMD
在CMD中运行以下命令。
setx OSS_ACCESS_KEY_ID "YOUR_ACCESS_KEY_ID" setx OSS_ACCESS_KEY_SECRET "YOUR_ACCESS_KEY_SECRET"运行以下命令,检查环境变量是否生效。
echo %OSS_ACCESS_KEY_ID% echo %OSS_ACCESS_KEY_SECRET%
PowerShell
在PowerShell中运行以下命令。
[Environment]::SetEnvironmentVariable("OSS_ACCESS_KEY_ID", "YOUR_ACCESS_KEY_ID", [EnvironmentVariableTarget]::User) [Environment]::SetEnvironmentVariable("OSS_ACCESS_KEY_SECRET", "YOUR_ACCESS_KEY_SECRET", [EnvironmentVariableTarget]::User)运行以下命令,检查环境变量是否生效。
[Environment]::GetEnvironmentVariable("OSS_ACCESS_KEY_ID", [EnvironmentVariableTarget]::User) [Environment]::GetEnvironmentVariable("OSS_ACCESS_KEY_SECRET", [EnvironmentVariableTarget]::User)
参考上述方式修改系统环境变量后,需重启或刷新编译运行环境,包括IDE、命令行界面、其他桌面应用程序及后台服务,以确保最新的系统环境变量成功加载。
使用环境变量传递凭证信息。
import com.aliyun.oss.ClientBuilderConfiguration; import com.aliyun.oss.OSS; import com.aliyun.oss.OSSClientBuilder; import com.aliyun.oss.common.auth.CredentialsProviderFactory; import com.aliyun.oss.common.auth.EnvironmentVariableCredentialsProvider; import com.aliyun.oss.common.comm.SignVersion; public class AkDemoTest { public static void main(String[] args) throws Exception { // 从环境变量中获取凭证 EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider(); // 使用credentialsProvider进行后续操作... ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration(); clientBuilderConfiguration.setSignatureVersion(SignVersion.V4); // 创建OSSClient实例。 // 当OSSClient实例不再使用时,调用shutdown方法以释放资源。 OSS ossClient = OSSClientBuilder.create() .endpoint("endpoint") .credentialsProvider(credentialsProvider) .clientConfiguration(clientBuilderConfiguration) .region("region") .build(); ossClient.shutdown(); } }
静态凭证
以下示例代码展示了对访问凭据直接进行硬编码,显式设置要使用的访问密钥的方法。
请勿将访问凭据嵌入到生产环境的应用程序中,此方法仅用于测试目的。
import com.aliyun.oss.ClientBuilderConfiguration;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.common.auth.CredentialsProvider;
import com.aliyun.oss.common.auth.DefaultCredentialProvider;
import com.aliyun.oss.common.comm.SignVersion;
public class AkDemoTest {
public static void main(String[] args) throws Exception {
// 填写RAM用户的Access Key ID和Access Key Secret
String accessKeyId = "yourAccessKeyID";
String accessKeySecret = "yourAccessKeySecret";
// 使用DefaultCredentialProvider方法直接设置AK和SK
CredentialsProvider credentialsProvider = new DefaultCredentialProvider(accessKeyId, accessKeySecret);
// 使用credentialsProvider初始化客户端
ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
// 显式声明使用 V4 签名算法
clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);
// 创建OSSClient实例。
// 当OSSClient实例不再使用时,调用shutdown方法以释放资源。
OSS ossClient = OSSClientBuilder.create()
.endpoint("endpoint")
.credentialsProvider(credentialsProvider)
.clientConfiguration(clientBuilderConfiguration)
.region("region")
.build();
ossClient.shutdown();
}
}使用STS临时访问凭证
适用于应用程序需要临时访问OSS的场景。通过STS服务获取的临时身份凭证(Access Key ID、Access Key Secret和Security Token)初始化凭证提供者。该方式需要手动维护STS Token,存在安全性风险和维护复杂度增加的风险。如果需要多次临时访问OSS,需要手动刷新STS Token。
通过OpenAPI方式简单快速获取STS临时访问凭证,请参见AssumeRole - 获取扮演角色的临时身份凭证。
通过SDK方式获取STS临时访问凭证,请参见使用STS临时访问凭证访问OSS。
请注意,STS Token在生成的时候需要指定过期时间,过期后自动失效不能再使用。
获取关于STS服务的接入点列表,请参见服务接入点。
环境变量
使用临时身份凭证设置环境变量。
Mac OS/Linux/Unix
重要请注意,此处使用的是通过STS服务获取的临时身份凭证(Access Key ID、Access Key Secret和Security Token),而非RAM用户的Access Key和Access Key Secret。
请注意区分STS服务获取的Access Key ID以STS开头,例如“STS.****************”。
export OSS_ACCESS_KEY_ID=<STS_ACCESS_KEY_ID> export OSS_ACCESS_KEY_SECRET=<STS_ACCESS_KEY_SECRET> export OSS_SESSION_TOKEN=<STS_SECURITY_TOKEN>Windows
重要请注意,此处使用的是通过STS服务获取的临时身份凭证(Access Key ID、Access Key Secret和Security Token),而非RAM用户的AK(Access Key ID、Access Key Secret)。
请注意区分STS服务获取的Access Key ID以STS开头,例如“STS.****************”。
set OSS_ACCESS_KEY_ID=<STS_ACCESS_KEY_ID> set OSS_ACCESS_KEY_SECRET=<STS_ACCESS_KEY_SECRET> set OSS_SESSION_TOKEN=<STS_SECURITY_TOKEN>通过环境变量传递凭证信息。
import com.aliyun.oss.ClientBuilderConfiguration; import com.aliyun.oss.OSS; import com.aliyun.oss.OSSClientBuilder; import com.aliyun.oss.common.auth.CredentialsProviderFactory; import com.aliyun.oss.common.auth.EnvironmentVariableCredentialsProvider; import com.aliyun.oss.common.comm.SignVersion; public class StsDemoTest { public static void main(String[] args) throws Exception { // 从环境变量中获取凭证 EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider(); // 使用credentialsProvider初始化客户端 ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration(); // 显式声明使用 V4 签名算法 clientBuilderConfiguration.setSignatureVersion(SignVersion.V4); // 创建OSSClient实例。 // 当OSSClient实例不再使用时,调用shutdown方法以释放资源。 OSS ossClient = OSSClientBuilder.create() .endpoint("endpoint") .credentialsProvider(credentialsProvider) .clientConfiguration(clientBuilderConfiguration) .region("region") .build(); ossClient.shutdown(); } }
静态凭证
可以在应用程序中对凭据直接进行硬编码,显式设置要使用的临时访问密钥。
import com.aliyun.oss.ClientBuilderConfiguration;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.common.auth.CredentialsProvider;
import com.aliyun.oss.common.auth.DefaultCredentialProvider;
import com.aliyun.oss.common.comm.SignVersion;
public class StsDemoTest {
public static void main(String[] args) throws Exception {
// 请设置为您通过STS服务获取的临时身份凭证Access Key ID、Access Key Secret和Security Token,而非RAM用户的身份凭证信息
// 请注意区分STS服务获取的Access Key ID是以STS开头,如下所示
String accessKeyId = "STS.****************";
String accessKeySecret = "yourAccessKeySecret";
String stsToken= "yourSecurityToken";
// 使用DefaultCredentialProvider方法直接设置AK和SK
CredentialsProvider credentialsProvider = new DefaultCredentialProvider(accessKeyId, accessKeySecret, stsToken);
// 使用credentialsProvider初始化客户端
ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
// 显式声明使用 V4 签名算法
clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);
// 创建OSSClient实例。
// 当OSSClient实例不再使用时,调用shutdown方法以释放资源。
OSS ossClient = OSSClientBuilder.create()
.endpoint("endpoint")
.credentialsProvider(credentialsProvider)
.clientConfiguration(clientBuilderConfiguration)
.region("region")
.build();
ossClient.shutdown();
}
}使用RAMRoleARN
适用于应用程序需要授权访问OSS,例如跨阿里云账号访问OSS的场景。通过指定RAM角色的ARN(Alibabacloud Resource Name)初始化凭证提供者,底层实现基于STS Token。Credentials工具会前往STS服务获取STS Token,并在会话到期前调用AssumeRole接口申请新的STS Token。还可以通过为policy赋值来限制RAM角色到一个更小的权限集合。
阿里云账号拥有资源的全部权限,AK一旦泄露,会给系统带来巨大风险,不建议使用。推荐使用最小化授权的RAM用户的AK。
如需创建RAM用户的AK,请直接访问创建AccessKey。RAM用户的Access Key ID、Access Key Secret信息仅在创建时显示,请及时保存,如若遗忘请创建新的AK进行轮换。
如需获取RAMRoleARN,请直接访问CreateRole - 创建角色。
添加credentials依赖。
<!-- https://mvnrepository.com/artifact/com.aliyun/credentials-java --> <dependency> <groupId>com.aliyun</groupId> <artifactId>credentials-java</artifactId> <version>LATEST</version> </dependency>配置AK和RAMRoleARN作为访问凭证。
import com.aliyun.credentials.models.CredentialModel; import com.aliyun.oss.ClientBuilderConfiguration; import com.aliyun.oss.OSS; import com.aliyun.oss.OSSClientBuilder; import com.aliyun.oss.common.auth.Credentials; import com.aliyun.oss.common.auth.CredentialsProvider; import com.aliyun.oss.common.auth.DefaultCredentials; import com.aliyun.oss.common.comm.SignVersion; public class RamRoleArnAkDemoTest { public static void main(String[] args) { com.aliyun.credentials.models.Config config = new com.aliyun.credentials.models.Config(); // 访问凭证类型。固定为ram_role_arn config.setType("ram_role_arn"); // 要扮演的RAM角色ARN,示例值:acs:ram::123456789012****:role/adminrole,可以通过环境变量ALIBABA_CLOUD_ROLE_ARN设置RoleArn config.setRoleArn("<RoleArn>"); // 从环境变量中获取AccessKeyId config.setAccessKeyId(System.getenv().get("ALIBABA_CLOUD_ACCESS_KEY_ID")); // 从环境变量中获取AccessKeySecret config.setAccessKeySecret(System.getenv().get("ALIBABA_CLOUD_ACCESS_KEY_SECRET")); // 角色会话名称,可以通过环境变量ALIBABA_CLOUD_ROLE_SESSION_NAME设置RoleSessionName config.setRoleName("<RoleSessionName>"); // 设置更小的权限策略,非必填。示例值:{"Statement": [{"Action": ["*"],"Effect": "Allow","Resource": ["*"]}],"Version":"1"} config.setPolicy("<Policy>"); // 设置角色会话有效期,非必填 config.setRoleSessionExpiration(3600); final com.aliyun.credentials.Client credentialsClient = new com.aliyun.credentials.Client(config); CredentialsProvider credentialsProvider = new CredentialsProvider(){ @Override public void setCredentials(Credentials credentials) { } @Override public Credentials getCredentials() { CredentialModel credential = credentialsClient.getCredential(); return new DefaultCredentials(credential.getAccessKeyId(), credential.getAccessKeySecret(), credential.getSecurityToken()); } }; // 使用credentialsProvider初始化客户端 ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration(); // 显式声明使用 V4 签名算法 clientBuilderConfiguration.setSignatureVersion(SignVersion.V4); // 创建OSSClient实例。 // 当OSSClient实例不再使用时,调用shutdown方法以释放资源。 OSS ossClient = OSSClientBuilder.create() .endpoint("endpoint") .credentialsProvider(credentialsProvider) .clientConfiguration(clientBuilderConfiguration) .region("region") .build(); ossClient.shutdown(); } }
使用ECSRAMRole
适用于应用程序运行在ECS实例、ECI实例、容器服务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 V1时,如出现以下类似错误,表明工程中存在包冲突问题。
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/http/ssl/TrustStrategy at com.aliyun.oss.OSSClient.<init>(OSSClient.java:268) at com.aliyun.oss.OSSClient.<init>(OSSClient.java:193) at com.aliyun.oss.demo.HelloOSS.main(HelloOSS.java:77) Caused by: java.lang.ClassNotFoundException: org.apache.http.ssl.TrustStrategy at java.net.URLClassLoader$1.run(URLClassLoader.java:366) at java.net.URLClassLoader$1.run(URLClassLoader.java:355) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:354) at java.lang.ClassLoader.loadClass(ClassLoader.java:425) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308) at java.lang.ClassLoader.loadClass(ClassLoader.java:358) ... 3 more或
Exception in thread "main" java.lang.NoSuchFieldError: INSTANCE at org.apache.http.impl.io.DefaultHttpRequestWriterFactory.<init>(DefaultHttpRequestWriterFactory.java:52) at org.apache.http.impl.io.DefaultHttpRequestWriterFactory.<init>(DefaultHttpRequestWriterFactory.java:56) at org.apache.http.impl.io.DefaultHttpRequestWriterFactory.<clinit>(DefaultHttpRequestWriterFactory.java:46) at org.apache.http.impl.conn.ManagedHttpClientConnectionFactory.<init>(ManagedHttpClientConnectionFactory.java:82) at org.apache.http.impl.conn.ManagedHttpClientConnectionFactory.<init>(ManagedHttpClientConnectionFactory.java:95) at org.apache.http.impl.conn.ManagedHttpClientConnectionFactory.<init>(ManagedHttpClientConnectionFactory.java:104) at org.apache.http.impl.conn.ManagedHttpClientConnectionFactory.<clinit>(ManagedHttpClientConnectionFactory.java:62) at org.apache.http.impl.conn.PoolingHttpClientConnectionManager$InternalConnectionFactory.<init>(PoolingHttpClientConnectionManager.java:572) at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.<init>(PoolingHttpClientConnectionManager.java:174) at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.<init>(PoolingHttpClientConnectionManager.java:158) at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.<init>(PoolingHttpClientConnectionManager.java:149) at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.<init>(PoolingHttpClientConnectionManager.java:125) at com.aliyun.oss.common.comm.DefaultServiceClient.createHttpClientConnectionManager(DefaultServiceClient.java:237) at com.aliyun.oss.common.comm.DefaultServiceClient.<init>(DefaultServiceClient.java:78) at com.aliyun.oss.OSSClient.<init>(OSSClient.java:268) at com.aliyun.oss.OSSClient.<init>(OSSClient.java:193) at OSSManagerImpl.upload(OSSManagerImpl.java:42) at OSSManagerImpl.main(OSSManagerImpl.java:63)错误原因是OSS Java SDK V1使用Apache HttpClient 4.4.1版本,而工程使用了与此版本冲突的Apache HttpClient或commons-httpclient jar包。在工程目录下执行
mvn dependency:tree命令可查看工程使用的jar包及版本。如下图所示,工程使用了与标准版本冲突的Apache HttpClient 4.3版本:
解决方法
包冲突有以下两种解决方法:
使用统一版本:如果工程使用与Apache HttpClient 4.4.1冲突的版本,统一使用4.4.1版本,并在pom.xml中删除其它版本的Apache HttpClient依赖。如果工程使用了commons-httpclient,同样可能存在冲突,需删除commons-httpclient依赖。
解决依赖冲突:如果工程依赖多个第三方包,而第三方包又依赖不同版本的Apache HttpClient,工程将出现依赖冲突,使用exclusion标签解除冲突。详细信息请参见Maven Guides。
OSS Java SDK V1依赖以下版本的包,冲突解决办法与HttpClient类似:

缺少包
错误原因
使用OSS Java SDK V1时,如出现以下类似错误,表明工程中缺少编译或运行OSS Java SDK V1所必需的包。
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/http/auth/Credentials at com.aliyun.oss.OSSClient.<init>(OSSClient.java:268) at com.aliyun.oss.OSSClient.<init>(OSSClient.java:193) at com.aliyun.oss.demo.HelloOSS.main(HelloOSS.java:76) Caused by: java.lang.ClassNotFoundException: org.apache.http.auth.Credentials at java.net.URLClassLoader$1.run(URLClassLoader.java:366) at java.net.URLClassLoader$1.run(URLClassLoader.java:355) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:354) at java.lang.ClassLoader.loadClass(ClassLoader.java:425) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308) at java.lang.ClassLoader.loadClass(ClassLoader.java:358) ... 3 more或
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/http/protocol/HttpContext at com.aliyun.oss.OSSClient.<init>(OSSClient.java:268) at com.aliyun.oss.OSSClient.<init>(OSSClient.java:193) at com.aliyun.oss.demo.HelloOSS.main(HelloOSS.java:76) Caused by: java.lang.ClassNotFoundException: org.apache.http.protocol.HttpContext at java.net.URLClassLoader$1.run(URLClassLoader.java:366) at java.net.URLClassLoader$1.run(URLClassLoader.java:355) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:354) at java.lang.ClassLoader.loadClass(ClassLoader.java:425) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308) at java.lang.ClassLoader.loadClass(ClassLoader.java:358) ... 3 more或
Exception in thread "main" java.lang.NoClassDefFoundError: org/jdom/input/SAXBuilder at com.aliyun.oss.internal.ResponseParsers.getXmlRootElement(ResponseParsers.java:645) at … … at com.aliyun.oss.OSSClient.doesBucketExist(OSSClient.java:471) at com.aliyun.oss.OSSClient.doesBucketExist(OSSClient.java:465) at com.aliyun.oss.demo.HelloOSS.main(HelloOSS.java:82) Caused by: java.lang.ClassNotFoundException: org.jdom.input.SAXBuilder at java.net.URLClassLoader$1.run(URLClassLoader.java:366) at java.net.URLClassLoader$1.run(URLClassLoader.java:355) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:354) at java.lang.ClassLoader.loadClass(ClassLoader.java:425) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308) at java.lang.ClassLoader.loadClass(ClassLoader.java:358) ... 11 moreOSS Java SDK V1依赖以下包:
aliyun-sdk-oss-2.2.1.jar
hamcrest-core-1.1.jar
jdom-1.1.jar
commons-codec-1.9.jar
httpclient-4.4.1.jar
commons-logging-1.2.jar
httpcore-4.4.1.jar
log4j-1.2.15.jar
其中log4j-1.2.15.jar为可选依赖,仅在需要日志功能时加入,其它包均为必需依赖。
解决方法
在工程中加入OSS Java SDK V1依赖的包,具体方法如下:
Eclipse项目:请参见安装 SDK。
Ant项目:将OSS Java SDK V1依赖的包放入工程的lib目录中。
直接编译:使用
-classpath或-cp命令指定OSS Java SDK V1依赖的包路径,或将依赖包放入classpath路径下。
连接超时
错误原因
运行OSS Java SDK V1程序时出现以下类似错误,可能原因为Endpoint配置错误或网络连接异常。
com.aliyun.oss.ClientException: SocketException at com.aliyun.oss.common.utils.ExceptionFactory.createNetworkException(ExceptionFactory.java:71) at com.aliyun.oss.common.comm.DefaultServiceClient.sendRequestCore(DefaultServiceClient.java:116) at com.aliyun.oss.common.comm.ServiceClient.sendRequestImpl(ServiceClient.java:121) at com.aliyun.oss.common.comm.ServiceClient.sendRequest(ServiceClient.java:67) at com.aliyun.oss.internal.OSSOperation.send(OSSOperation.java:92) at com.aliyun.oss.internal.OSSOperation.doOperation(OSSOperation.java:140) at com.aliyun.oss.internal.OSSOperation.doOperation(OSSOperation.java:111) at com.aliyun.oss.internal.OSSBucketOperation.getBucketInfo(OSSBucketOperation.java:1152) at com.aliyun.oss.OSSClient.getBucketInfo(OSSClient.java:1220) at com.aliyun.oss.OSSClient.getBucketInfo(OSSClient.java:1214) at com.aliyun.oss.demo.HelloOSS.main(HelloOSS.java:94) Caused by: org.apache.http.conn.HttpHostConnectException: Connect to oss-test.oss-cn-hangzhou-internal.aliyuncs.com:80 [oss-test.oss-cn-hangzhou-internal.aliyuncs.com/10.84.135.99] failed: Connection timed out: connect at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:151) at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:353) at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:380) at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:236) at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:184) at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110) at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184) at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82) at com.aliyun.oss.common.comm.DefaultServiceClient.sendRequestCore(DefaultServiceClient.java:113) ... 9 more解决方法
可以使用ossutil工具快速定位错误原因并解决问题。
报错SignatureDoesNotMatch
错误原因1:AccessKey信息不一致
AccessKey ID和AccessKey Secret不一致。获取AccessKey ID和AccessKey Secret的操作步骤请参见创建AccessKey。
错误原因2:签名URL使用不正确
签名URL使用错误示例如下:
GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, object); request.setExpiration( new Date(new Date().getTime() + 3600 * 1000)); request.addUserMetadata("author"); URL url = ossClient.generatePresignedUrl(request); Map<String, String> header = new HashMap<String, String>(); header.put("author"); ossClient.putObject(url, new ByteArrayInputStream("Hello OSS".getBytes()), -1, header);未指定Method参数时,默认使用GET方法,但以上为PutObject请求,应指定Method参数并设置为PUT方法。
通过PutObject发送请求时,请求Header中的自定义元数据必须以
x-oss-meta-为前缀。以上示例中的自定义元数据应改为x-oss-meta-author。解决方法:
指定Method参数,并修改Header前缀:
request.addUserMetadata("author"); request.setMethod(HttpMethod.PUT); URL url = ossClient.generatePresignedUrl(request); Map<String, String> header = new HashMap<String, String>(); header.put("x-oss-meta-" + "author"); ossClient.putObject(url, new ByteArrayInputStream("Hello OSS".getBytes()), -1, header);错误原因3:HttpClient版本兼容性问题
使用低于3.7.0版本的OSS SDK,同时项目中引入了4.5.9及以上版本的HttpClient。
上传的文件名中包含
+字符,4.5.9版本的HttpClient不会对+进行URLEncode编码,导致客户端与服务端计算的签名不一致。

解决方法:
OSS SDK升级至3.11.1及以上版本,以兼容4.5.9版本的HttpClient。
移除多余的HttpClient依赖。引入OSS SDK时会自动引入HttpClient依赖,如果第三方库另外引入了HttpClient,请参见包冲突解决方案。
错误原因4:HttpClient字符集兼容性问题
HttpClient 4.5.10版本不支持Header中包含ISO/9959-1标准以外的字符,但在项目中引入了4.5.10以上的httpclient,并在请求Header中包含了ISO/9959-1标准以外的字符,例如
x-oss-meta-开头的自定义元数据中传入了中文字符。
解决方法:
参见包冲突解决方案,移除冲突的HttpClient版本。
在请求Header中仅传入符合ISO/9959-1标准的字符。
报异常“Failed to parse the response result”

错误原因
客户端某些特殊的软件拦截了HTTP请求,或者公网路由劫持了HTTP请求。
在Java 9及以上的版本中使用OSS Java SDK V1,且未在pom.xml文件中添加JAXB相关依赖。
解决方法
切换为HTTPS请求。
添加JAXB相关依赖。操作步骤,请参见安装 SDK。
org.apache.http.NoHttpResponseException: The target server failed to respond
错误原因
运行OSS Java SDK V1程序时,出现以下类似错误:

使用过期连接会导致上述错误,该错误仅在Java SDK 2.1.2之前的版本出现。
解决方法
升级OSS Java SDK V1至2.1.2及以上版本。
JVM中存在大量org.apache.http.impl.conn.PoolingHttpClientConnectionManager实例
错误原因
ossClient未正确关闭。
解决方法
主动关闭已执行完毕的ossClient或使用单例模式。
调用OSS Java SDK V1不响应
错误原因
调用OSS Java SDK V1无响应。通过
jstack -l pid命令查看堆栈,问题出现在以下位置:"main" prio=6 tid=0x000000000291e000 nid=0xc40 waiting on condition [0x0000000002dae000] java.lang.Thread.State: WAITING (parking) at sun.misc.Unsafe.park(Native Method) - parking to wait for <0x00000007d85697f8> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject) at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186) at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2043) at org.apache.http.pool.PoolEntryFuture.await(PoolEntryFuture.java:138) at org.apache.http.pool.AbstractConnPool.getPoolEntryBlocking(AbstractConnPool.java:306) at org.apache.http.pool.AbstractConnPool.access$000(AbstractConnPool.java:64) at org.apache.http.pool.AbstractConnPool$2.getPoolEntry(AbstractConnPool.java:192) at org.apache.http.pool.AbstractConnPool$2.getPoolEntry(AbstractConnPool.java:185) at org.apache.http.pool.PoolEntryFuture.get(PoolEntryFuture.java:107) at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.leaseConnection(PoolingHttpClientConnectionManager.java:276) at org.apache.http.impl.conn.PoolingHttpClientConnectionManager$1.get(PoolingHttpClientConnectionManager.java:263) at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:190) at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:184) at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110) at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184) at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82) at com.aliyun.oss.common.comm.DefaultServiceClient.sendRequestCore(DefaultServiceClient.java:113) at com.aliyun.oss.common.comm.ServiceClient.sendRequestImpl(ServiceClient.java:123) at com.aliyun.oss.common.comm.ServiceClient.sendRequest(ServiceClient.java:68) at com.aliyun.oss.internal.OSSOperation.send(OSSOperation.java:94) at com.aliyun.oss.internal.OSSOperation.doOperation(OSSOperation.java:146) at com.aliyun.oss.internal.OSSOperation.doOperation(OSSOperation.java:113) at com.aliyun.oss.internal.OSSObjectOperation.getObject(OSSObjectOperation.java:229) at com.aliyun.oss.OSSClient.getObject(OSSClient.java:629) at com.aliyun.oss.OSSClient.getObject(OSSClient.java:617) at samples.HelloOSS.main(HelloOSS.java:49)原因为连接池中连接泄漏,可能是使用ossObject后未正确关闭。
解决方法
检查程序,确保没有连接泄漏。正确关闭方法如下:
// 读取文件 OSSObject ossObject = ossClient.getObject(bucketName, objectName); // OSS操作 // 关闭ossObject ossObject.close();问题排查的具体步骤请参见OSS Java SDK V1不响应问题排查。
连接关闭
错误原因
使用ossClient.getObject时,如出现以下类似错误:
Exception in thread "main" org.apache.http.ConnectionClosedException: Premature end of Content-Length delimited message body (expected: 11990526; received: 202880) at org.apache.http.impl.io.ContentLengthInputStream.read(ContentLengthInputStream.java:180) at org.apache.http.impl.io.ContentLengthInputStream.read(ContentLengthInputStream.java:200) at org.apache.http.impl.io.ContentLengthInputStream.close(ContentLengthInputStream.java:103) at org.apache.http.impl.execchain.ResponseEntityProxy.streamClosed(ResponseEntityProxy.java:128) at org.apache.http.conn.EofSensorInputStream.checkClose(EofSensorInputStream.java:228) at org.apache.http.conn.EofSensorInputStream.close(EofSensorInputStream.java:174) at java.io.FilterInputStream.close(FilterInputStream.java:181) at java.io.FilterInputStream.close(FilterInputStream.java:181) at com.aliyun.oss.event.ProgressInputStream.close(ProgressInputStream.java:147) at java.io.FilterInputStream.close(FilterInputStream.java:181) at samples.HelloOSS.main(HelloOSS.java:39)原因为两次读取数据间隔时间超过1分钟。OSS会关闭超过1分钟没有发送或接收数据的连接。
解决方法
如果每次仅读取部分数据,且处理数据的时间不固定,建议使用指定范围读取,避免数据读取时连接关闭。范围下载完成后,连接会自动关闭。详细信息请参见范围下载(Java SDK)。
内存泄露
错误原因
调用OSS Java SDK V1的程序运行一段时间(根据业务量,几小时到几天不等)后出现内存泄露。推荐使用Eclipse Memory Analyzer (MAT)分析内存使用情况。详细信息请参见使用MAT进行堆转储文件分析。
如果分析结果类似下图所示(PoolingHttpClientConnectionManager占96%的内存),原因为程序中可能多次执行
new OSSClient,但未调用ossClient.shutdown,造成内存泄漏。
解决方法
new OSSClient操作完成后,通过shutdown方法关闭,保证new OSSClient和ossClient.shutdown成对使用。
调用ossClient.shutdown报异常InterruptedException
错误原因
OSS Java SDK V1 2.3.0之前的版本在调用
ossClient.shutdown时报以下异常:java.lang.InterruptedException: sleep interrupted at java.lang.Thread.sleep(Native Method) at com.aliyun.oss.common.comm.IdleConnectionReaper.run(IdleConnectionReaper:76)原因为ossClient后台线程IdleConnectionReaper会定时关闭闲置连接。IdleConnectionReaper在Sleep时调用ossClient.shutdown,就会出现上述异常。
解决方法
使用以下代码忽略该异常:
try { ossClient.shutdown(); } catch(Exception e) { }
请求出现异常“SDK.ServerUnreachable : Speicified endpoint or uri is not valid”

错误原因
用户端STS并发请求过高。
网络到Server端超时。
所使用的STS SDK以及SDK core版本过旧。
解决方法
用户端STS并发请求过高,而用户端的ECS或本地PC性能不足以承载当时的并发量,降低OSS并发数。
用户网络到Server端出现超时现象,可通过抓包验证。
建议将STS SDK及SDK core升级至最新版本。
NoSuchKey

错误原因
源文件不存在。
解决方法
参见404错误排查方法。
SocketException

错误原因
可能是socket在初始化阶段失败,导致请求未到达OSS。
解决方法
建议从以下几个方面进行排查:
出现问题时是否有网络抖动。
主机的socket连接数是否占满。
确认出现问题时连接数是否超过SDK中设置的maxconnection,如果连接数超过maxconnection设置,也会出现socket异常。
如果以上都没有问题,建议部署tcpdump或Wireshark抓包,问题复现后分析数据包。
使用OSS PostObject的callback没有触发回调
使用OSS PostObject的callback没有触发回调,但通过PutObject使用同样的callback触发了回调。一般情况下,如果JSON格式有误或回调失败,都会返回相应的消息,需要分别测试Put和Post回调效果:

错误原因
发送请求时callback参数在file下面。

解决方法
调整callback参数与file的位置。

此时测试结果显示业务服务器成功抓取请求。

Connection pool shut down
Caused by: java.lang.IllegalStateException: Connection pool shut down
at org.apache.http.util.Asserts.check(Asserts.java:34)
at org.apache.http.pool.AbstractConnPool.lease(AbstractConnPool.java:184)
at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.requestConnection(PoolingHttpClientConnectionManager.java:251)
at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:175)
at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:184)
at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
at com.aliyun.oss.common.comm.DefaultServiceClient.sendRequestCore(DefaultServiceClient.java:124)
at com.aliyun.oss.common.comm.ServiceClient.sendRequestImpl(ServiceClient.java:133)
... 8 more错误原因
调用
ossClient.shutdown()接口后,仍继续通过ossClient发送请求。解决方法
检查调用逻辑,确保调用
ossClient.shutdown()接口后,不再通过ossClient发送请求。
使用Java SDK的generatePresignedUrl生成的请求报错Request has expired
错误原因
int类型溢出,导致2038年时间戳问题。
超出URL设置的过期时间后发起上传请求。
解决方法
如果是int类型溢出,建议Java SDK中过期时长不要超过2038年。
如果因超出URL设置的过期时间后发起上传请求,建议设置合理的过期时间,确保过期时间大于发起请求的时间。
报错Invalid Response或Implementation of JAXB-API has not been found on module path or classpath
错误原因
使用Java 9以上版本,并且未添加JAXB依赖。
解决方法
关于如何添加JAXB依赖的更多信息,请参见安装 SDK。
OSS Java SDK V1 中的 OSSClient 是线程安全的吗?
OSSClient 具备线程安全特性,允许多线程访问同一实例。结合业务需求,可以复用同一个OSSClient 实例,也可以创建多个 OSSClient 实例分别使用。
OSSClient 实例内部维护连接池。当 OSSClient 实例不再使用时,调用 shutdown 方法将其关闭,避免创建过多的 OSSClient 实例导致资源耗尽。
客户端网络正常,但是通过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日志:
