快速接入
通过以下步骤快速接入 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 more- OSS 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日志:
