活动

天翼云最新优惠活动,涵盖免费试用,产品折扣等,助您降本增效!
热门活动
  • 618智算钜惠季 爆款云主机2核4G限时秒杀,88元/年起!
  • 免费体验DeepSeek,上天翼云息壤 NEW 新老用户均可免费体验2500万Tokens,限时两周
  • 云上钜惠 HOT 爆款云主机全场特惠,更有万元锦鲤券等你来领!
  • 算力套餐 HOT 让算力触手可及
  • 天翼云脑AOne NEW 连接、保护、办公,All-in-One!
  • 中小企业应用上云专场 产品组合下单即享折上9折起,助力企业快速上云
  • 息壤高校钜惠活动 NEW 天翼云息壤杯高校AI大赛,数款产品享受线上订购超值特惠
  • 天翼云电脑专场 HOT 移动办公新选择,爆款4核8G畅享1年3.5折起,快来抢购!
  • 天翼云奖励推广计划 加入成为云推官,推荐新用户注册下单得现金奖励
免费活动
  • 免费试用中心 HOT 多款云产品免费试用,快来开启云上之旅
  • 天翼云用户体验官 NEW 您的洞察,重塑科技边界

智算服务

打造统一的产品能力,实现算网调度、训练推理、技术架构、资源管理一体化智算服务
智算云(DeepSeek专区)
科研助手
  • 算力商城
  • 应用商城
  • 开发机
  • 并行计算
算力互联调度平台
  • 应用市场
  • 算力市场
  • 算力调度推荐
一站式智算服务平台
  • 模型广场
  • 体验中心
  • 服务接入
智算一体机
  • 智算一体机
大模型
  • DeepSeek-R1-昇腾版(671B)
  • DeepSeek-R1-英伟达版(671B)
  • DeepSeek-V3-昇腾版(671B)
  • DeepSeek-R1-Distill-Llama-70B
  • DeepSeek-R1-Distill-Qwen-32B
  • Qwen2-72B-Instruct
  • StableDiffusion-V2.1
  • TeleChat-12B

应用商城

天翼云精选行业优秀合作伙伴及千余款商品,提供一站式云上应用服务
进入甄选商城进入云市场创新解决方案
办公协同
  • WPS云文档
  • 安全邮箱
  • EMM手机管家
  • 智能商业平台
财务管理
  • 工资条
  • 税务风控云
企业应用
  • 翼信息化运维服务
  • 翼视频云归档解决方案
工业能源
  • 智慧工厂_生产流程管理解决方案
  • 智慧工地
建站工具
  • SSL证书
  • 新域名服务
网络工具
  • 翼云加速
灾备迁移
  • 云管家2.0
  • 翼备份
资源管理
  • 全栈混合云敏捷版(软件)
  • 全栈混合云敏捷版(一体机)
行业应用
  • 翼电子教室
  • 翼智慧显示一体化解决方案

合作伙伴

天翼云携手合作伙伴,共创云上生态,合作共赢
天翼云生态合作中心
  • 天翼云生态合作中心
天翼云渠道合作伙伴
  • 天翼云代理渠道合作伙伴
天翼云服务合作伙伴
  • 天翼云集成商交付能力认证
天翼云应用合作伙伴
  • 天翼云云市场合作伙伴
  • 天翼云甄选商城合作伙伴
天翼云技术合作伙伴
  • 天翼云OpenAPI中心
  • 天翼云EasyCoding平台
天翼云培训认证
  • 天翼云学堂
  • 天翼云市场商学院
天翼云合作计划
  • 云汇计划
天翼云东升计划
  • 适配中心
  • 东升计划
  • 适配互认证

开发者

开发者相关功能入口汇聚
技术社区
  • 专栏文章
  • 互动问答
  • 技术视频
资源与工具
  • OpenAPI中心
开放能力
  • EasyCoding敏捷开发平台
培训与认证
  • 天翼云学堂
  • 天翼云认证
魔乐社区
  • 魔乐社区

支持与服务

为您提供全方位支持与服务,全流程技术保障,助您轻松上云,安全无忧
文档与工具
  • 文档中心
  • 新手上云
  • 自助服务
  • OpenAPI中心
定价
  • 价格计算器
  • 定价策略
基础服务
  • 售前咨询
  • 在线支持
  • 在线支持
  • 工单服务
  • 建议与反馈
  • 用户体验官
  • 服务保障
  • 客户公告
  • 会员中心
增值服务
  • 红心服务
  • 首保服务
  • 客户支持计划
  • 专家技术服务
  • 备案管家

了解天翼云

天翼云秉承央企使命,致力于成为数字经济主力军,投身科技强国伟大事业,为用户提供安全、普惠云服务
品牌介绍
  • 关于天翼云
  • 智算云
  • 天翼云4.0
  • 新闻资讯
  • 天翼云APP
基础设施
  • 全球基础设施
  • 信任中心
最佳实践
  • 精选案例
  • 超级探访
  • 云杂志
  • 分析师和白皮书
  • 天翼云·创新直播间
市场活动
  • 2025智能云生态大会
  • 2024智算云生态大会
  • 2023云生态大会
  • 2022云生态大会
  • 天翼云中国行
天翼云
  • 活动
  • 智算服务
  • 产品
  • 解决方案
  • 应用商城
  • 合作伙伴
  • 开发者
  • 支持与服务
  • 了解天翼云
      • 文档
      • 控制中心
      • 备案
      • 管理中心
      文档中心

      对象存储(经典版)I型

      对象存储(经典版)I型

        • 产品动态
        • 产品简介
        • 产品定义
        • 产品优势
        • 功能特性
        • 应用场景
        • 主要概念
        • 存储桶和文件
        • Account、Service、Bucket和Object
        • 存储类型
        • 合规保留
        • 清单配置
        • 统计分析
        • 操作跟踪
        • 访问控制
        • 数据安全
        • 使用限制
        • 与其他服务的关系
        • 计费说明
        • 计费模式
        • 计费项
        • 按需计费
        • 资源包计费
        • 到期
        • 欠费
        • 快速入门
        • 相关术语解释
        • 服务开通
        • 订购须知
        • 开通OOS服务
        • 资源包订购
        • 资源包续订
        • 资源包退订
        • 控制台快速入门
        • 进入控制台
        • 地域切换
        • 创建存储桶
        • 上传文件
        • 下载文件
        • 控制台指南
        • 进入控制台
        • 域名(Endpoint)
        • 域名(Endpoint)列表
        • 地域切换
        • IAM用户操作权限要求
        • 统计概览
        • 统计概述
        • 概览
        • 统计
        • 容量
        • 删除量
        • 流量
        • 请求次数
        • 并发连接数
        • 数据取回
        • 存储桶管理
        • 存储桶(Bucket)概述
        • 创建存储桶(Bucket)
        • 存储桶列表
        • 删除存储桶(Bucket)
        • 清空存储桶
        • 查看/修改存储桶属性
        • 区域属性
        • 安全策略
        • 网站
        • 日志
        • 生命周期
        • 跨域设置
        • 合规保留
        • 清单配置
        • 文件管理
        • 文件概述
        • 文件列表
        • 查看文件详细信息
        • 上传文件
        • 下载文件
        • 管理文件元数据
        • 预览文件
        • 分享文件
        • 创建文件夹
        • 删除文件或文件夹
        • 复制文件
        • 移动文件
        • 修改存储类型
        • 搜索文件或文件夹
        • 复制文件名称
        • 文件排序
        • 操作跟踪
        • 操作跟踪概述
        • 管理事件记录
        • 跟踪列表
        • 访问控制
        • 访问控制概述
        • 快速入门
        • IAM用户
        • 创建IAM用户
        • 查看和修改IAM用户信息
        • 删除用户
        • IAM子用户登录
        • IAM用户组
        • 创建用户组
        • 查看和修改用户组信息
        • 删除用户组
        • IAM策略
        • 概述
        • IAM策略编写规则
        • Version
        • Statement
        • 系统策略
        • 自定义策略
        • 新建自定义策略
        • 修改自定义策略
        • 删除自定义策略
        • 查看策略基本信息
        • 授权用户/用户组
        • 安全设置
        • 密码安全设置
        • 登录安全设置
        • 安全凭证
        • 密钥
        • 密码
        • MFA
        • 资源包管理
        • API参考
        • 安全策略
        • 用户签名验证(V2)
        • Header中包含签名
        • 使用查询参数验证
        • 用户签名验证(V4)
        • Signature Version 4的工作原理
        • 认证方法
        • 使用Authorization请求头验证
        • 使用查询参数验证
        • Bucket权限控制
        • 访问控制
        • Bucket Policy安全策略
        • 介绍
        • Bucket Policy元素
        • 示例
        • 合规保留
        • 存储桶(Bucket)和文件(Object)
        • OOS API请求结构
        • 关于Service的操作
        • Get Service (List Buckets)
        • Get Regions
        • 关于Bucket的操作
        • PUT Bucket
        • Get Bucket Location
        • GET Bucket ACL
        • GET Bucket (List Objects)
        • DELETE Bucket
        • PUT Bucket Policy
        • GET Bucket Policy
        • DELETE Bucket Policy
        • PUT Bucket Website
        • GET Bucket Website
        • DELETE Bucket Website
        • List Multipart Uploads
        • PUT Bucket Logging
        • GET Bucket Logging
        • HEAD Bucket
        • PUT Bucket Lifecycle
        • GET Bucket Lifecycle
        • DELETE Bucket Lifecycle
        • PUT Bucket CORS
        • GET Bucket CORS
        • DELETE Bucket CORS
        • PUT Bucket Object Lock
        • GET Bucket Object Lock
        • DELETE Bucket Object Lock
        • PUT Bucket Inventory Configuration
        • GET Bucket Inventory Configuration
        • List Bucket Inventory Configuration
        • DELETE Bucket Inventory Configuration
        • 关于Object的操作
        • PUT Object
        • GET Object
        • DELETE Object
        • PUT Object - Copy
        • Initial Multipart Upload
        • Upload Part
        • Complete Multipart Upload
        • Abort Multipart Upload
        • List Parts
        • Copy Part
        • Delete Multiple Objects
        • 断点续传
        • POST Object
        • OPTIONS Object
        • 生成共享链接
        • HEAD Object
        • Backoff说明
        • 错误响应
        • REST错误响应
        • 错误码列表
        • 统计分析
        • 统计API请求结构
        • 统计API概览
        • 统计API
        • GetCapacity
        • GetBilledStorageUsage
        • GetRestoreCapacity
        • GetDeleteCapacity
        • GetTraffics
        • GetRequests
        • GetReturnCode
        • GetConcurrentConnection
        • GetUsage
        • GetBandwidth
        • 错误码列表
        • 操作跟踪
        • 操作跟踪API请求结构
        • 操作跟踪API概览
        • 操作跟踪API
        • CreateTrail
        • DeleteTrail
        • DescribeTrails
        • GetTrailStatus
        • PutEventSelectors
        • GetEventSelectors
        • UpdateTrail
        • StartLogging
        • StopLogging
        • LookupEvents
        • 错误码列表
        • 操作跟踪记录事件列表
        • 访问控制(IAM)
        • IAM API请求结构
        • 访问控制API概览
        • 用户管理接口
        • CreateUser
        • GetUser
        • ListUsers
        • DeleteUser
        • TagUser
        • UntagUser
        • ListUserTags
        • ListGroupForUser
        • CreateAccessKey
        • ListAccessKeys
        • GetAccessKeyLastUsed
        • UpdateAccessKey
        • DeleteAccessKey
        • GetSessionToken
        • CreateLoginProfile
        • GetLoginProfile
        • UpdateLoginProfile
        • DeleteLoginProfile
        • ChangePassword
        • CreateVirtualMFADevice
        • EnableMFADevice
        • ListVirtualMFADevices
        • ListMFADevices
        • DeactivateMFADevice
        • DeleteVirtualMFADevice
        • 用户组管理接口
        • CreateGroup
        • GetGroup
        • AddUserToGroup
        • RemoveUserFromGroup
        • ListGroups
        • DeleteGroup
        • 权限策略管理接口
        • CreatePolicy
        • GetPolicy
        • ListPolicies
        • ListEntitiesForPolicy
        • DeletePolicy
        • AttachUserPolicy
        • ListAttachedUserPolicies
        • DetachUserPolicy
        • AttachGroupPolicy
        • ListAttachedGroupPolicies
        • DetachGroupPolicy
        • UpdateAccountPasswordPolicy
        • GetAccountPasswordPolicy
        • DeleteAccountPasswordPolicy
        • UpdateAccountLoginSecurityPolicy
        • GetAccountLoginSecurityPolicy
        • DeleteAccountLoginSecurityPolicy
        • 服务数量查询
        • 错误码列表
        • IAM策略编写规则
        • 操作权限与API对应关系
        • 常用工具
        • OOS数据迁移工具
        • 介绍
        • 运行环境
        • 迁移步骤
        • 迁移配置文件示例
        • 常见问题
        • 最佳实践
        • 生命周期管理存储桶文件
        • 分享文件
        • 降低恶意访问风险
        • 设置跨域访问
        • 使用S3 Java SDK访问OOS
        • IAM最佳实践
        • 安全管理
        • 用户管理
        • STS临时授权示例
        • 授予其他主账号及主账户下子账号操作名下存储桶的权限
        • 同地域实现内网访问OOS
        • 数据一致性校验
        • 性能优化
        • 使用HttpURLConnection开发
        • 使用V2签名时的HttpURLConnection开发
        • 使用V4签名时的HttpURLConnection开发
        • 数据迁移
        • 本地数据迁移到OOS
        • AWS S3数据迁移到OOS
        • 阿里云OSS数据迁移到OOS
        • OOS之间的数据迁移
        • 图片处理
        • 应用场景
        • 主要概念
        • 参数说明
        • URL构成规则
        • 规则说明
        • 用户签名
        • 接口
        • 图像处理接口
        • 图片水印接口
        • 管道
        • 图片拼接成GIF接口
        • 示例
        • 示例链接
        • 示例代码
        • 常见问题
        • 计费类
        • 计费类常见问题
        • 资源包是否必须购买?是否能指定给具体的存储桶使用?
        • 已购买资源包,为什么仍然扣费?
        • 存储桶内无文件,为什么会产生流量?
        • 哪些资源包会按月更新额度,哪些不会?
        • 如何关闭OOS服务或停止计费?
        • 存储容量和流出流量的关系?
        • 购买类
        • 产品咨询类
        • 产品咨询类常见问题
        • 什么是对象存储网络?
        • 可以上传什么样的文件,大小是否有限制?
        • 什么是存储桶的索引位置和数据位置?
        • 可以在OOS中存储多少数据?
        • OOS是否有图形化管理工具或者命令行工具,帮助用户上传数据到OOS?
        • OOS的持久性和可用性如何?
        • OOS有哪些数据访问方法?
        • 如何保障OOS用户数据的安全?
        • OOS与自建服务器存储对比?
        • 为什么通过OOS控制台访问OOS中的资源时被强制下载?
        • 存储桶(Bucket)和文件(Object)类
        • 存储桶(Bucket)和文件(Object)常见问题
        • 如何创建存储桶(Bucket)?
        • 应该如何使用Bucket?
        • 如何选择使用哪个地域的OOS?
        • 生命周期管理支持哪些场景?
        • 如何获取存储桶的静态网站托管地址?
        • 如何绑定自己的域名?
        • 可以对OOS Bucket进行重命名吗?是否支持Object迁移?
        • OOS支持Bucket作为域名的访问方式吗?
        • 图片上传到OOS,可否生成url,实现图片通过url直接访问预览?
        • 如何获取OOS文件的访问地址?
        • 怎么删除存储桶中的全部文件?
        • 统计分析类
        • 操作跟踪类
        • 访问控制类
        • 访问控制常见问题
        • 新版的IAM与旧版的IAM相比有什么区别?
        • 在绑定MFA页面,输入两组安全码后,提示安全码错误,怎么办?
        • API/SDK类
        • API/SDK常见问题
        • OOS兼容哪些Amazons S3 API?
        • 图片处理类
        • 工具类
        • 视频专区
        • 文档下载
        • OOS开发者文档
        • 用户手册
        • SDK及开发指南
        • 常用工具
        • 相关协议
        • 中国电信天翼云对象存储服务协议
        • 中国电信天翼云对象存储服务等级协议
          无相关产品

          本页目录

          帮助中心对象存储(经典版)I型最佳实践使用HttpURLConnection开发使用V2签名时的HttpURLConnection开发
          使用V2签名时的HttpURLConnection开发
          更新时间 2024-06-19 15:05:41
          • 新浪微博
          • 微信
            扫码分享
          • 复制链接
          最近更新时间: 2024-06-19 15:05:41
          分享文章
          • 新浪微博
          • 微信
            扫码分享
          • 复制链接
          本节主要介绍使用V2签名时的HttpURLConnection开发。

          应用场景

          V2签名下,使用HttpURLConnection开发。

          前提条件

          已开通对象存储(经典版)Ⅰ型服务。

          具体操作

          可以参考下列示例进行HttpURLConnection开发。

          import java.io.BufferedReader;
          import java.io.InputStream;
          import java.io.InputStreamReader;
          import java.io.OutputStream;
          import java.io.UnsupportedEncodingException;
          import java.net.HttpURLConnection;
          import java.net.URL;
          import java.net.URLEncoder;
          import java.nio.charset.StandardCharsets;
          import java.text.SimpleDateFormat;
          import java.util.Arrays;
          import java.util.Base64;
          import java.util.Date;
          import java.util.HashMap;
          import java.util.Iterator;
          import java.util.List;
          import java.util.Locale;
          import java.util.Map;
          import java.util.SortedMap;
          import java.util.TimeZone;
          import java.util.TreeMap;
          
          import javax.crypto.Mac;
          import javax.crypto.spec.SecretKeySpec;
          
          public class OOSDemoForV2Signer {
              private static final String DATE_STR = "EEE, d MMM yyyy HH:mm:ss 'GMT'";
              private static final SimpleDateFormat DATE_FMT = new SimpleDateFormat(DATE_STR, Locale.ENGLISH);
              static {
                  TimeZone gmt = TimeZone.getTimeZone("GMT");
                  DATE_FMT.setTimeZone(gmt);
              }
          
              private static final String OOS_ACCESS_KEY = "your ak";
              private static final String OOS_SECRET_KEY = "your sk";
              private static final String OOS_ENDPOINT = "oos-cn.ctyunapi.cn";
              private static final String OOS_OBJECT_CONTENT = "your_object_content";
          
              private static final int CONN_TIMEOUT = 30000;
              private static final int READ_TIMEOUT = 30000;
          
              public void putObject(String bucket, String objectKey) {
                  try {
                      Map<String, String> headers = new HashMap<>();
                      headers.put("Content-Type", "text/plain");
                      headers.put("x-amz-date", "xxxx");
                      HttpURLConnection connection = generateConnection("PUT", bucket, objectKey, headers);
                      connection.setFixedLengthStreamingMode(OOS_OBJECT_CONTENT.length());
                      connection.setDoOutput(true);
                      connection.connect();
                      byte[] requestBody = OOS_OBJECT_CONTENT.getBytes();
                      try (OutputStream outputStream = connection.getOutputStream()) {
                          outputStream.write(requestBody);
                      }
                      int responseCode = connection.getResponseCode();
                      if (responseCode == 200) {
                          System.out.println("put object success");
                      } else {
                          try (InputStream inputStream = connection.getErrorStream()) {
                              BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
                              String line;
                              while ((line = reader.readLine()) != null) {
                                  System.out.println(line);
                              }
                          }
                      }
                  } catch (Exception e) {
                      e.printStackTrace();
                  }
              }
          
              public void getObject(String bucket, String objectKey) {
                  try {
                      HttpURLConnection connection = generateConnection("GET", bucket, objectKey, null);
                      connection.connect();
                      int responseCode = connection.getResponseCode();
                      // 在responseCode为200 的情况下, 可将connection.getInputStream()的对象数据读出。
                      if (responseCode == 200) {
                          System.out.println("get object success");
                      }
                      try (InputStream inputStream =
                                   responseCode == 200 ? connection.getInputStream() : connection.getErrorStream()) {
                          BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
                          String line;
                          while ((line = reader.readLine()) != null) {
                              System.out.println(line);
                          }
                      }
                  } catch (Exception e) {
                      // 异常可选择抛出或者处理掉。
                      e.printStackTrace();
                  }
              }
          
              public void deleteObject(String bucket, String objectKey) {
                  try {
                      HttpURLConnection connection = generateConnection("DELETE", bucket, objectKey, null);
                      connection.connect();
                      int responseCode = connection.getResponseCode();
                      if (responseCode == 204) {
                          System.out.println("delete object success");
                      } else {
                          try (InputStream inputStream = connection.getErrorStream()) {
                              BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
                              String line;
                              while ((line = reader.readLine()) != null) {
                                  System.out.println(line);
                              }
                          }
                      }
                  } catch (Exception e) {
                      // 异常可选择抛出或者处理掉。
                      e.printStackTrace();
                  }
              }
          
              /**
               * 1 并不是headers里的所有头域,都参与计算签名。详情请参照<a href=
               * "https://oos-cn.ctyunapi.cn/docs/oos/OOS%E5%BC%80%E5%8F%91%E8%80%85%E6%96%87%E6%A1%A3-v6.pdf"> OOS开发者文档-v6
               * </a>3.1.1章节StringToSign的构成说明 </br>
               * 2 任何头以x-amz-meta-这个前缀开始都会被认为是用户的元数据,当用户检索时,它将会和对象一起被存储并返回。 PUT请求头大小限制为8KiB。在PUT请求头中,用户定义的元数据大小限制为2KiB。</br>
               * 例:headers.put("x-amz-meta-test", "oos");
               */
              private HttpURLConnection generateConnection(String method, String bucket, String objectKey,
                                                           Map<String, String> headers) throws Exception {
          
                  if (headers == null) {
                      headers = new TreeMap<>();
                  }
                  if (!headers.containsKey("Date")) {
                      String date = DATE_FMT.format(new Date());
                      headers.put("Date", date);
                  }
                  Map<String, String> querys = new HashMap<>(32);
                  // 设置查询参数示例,可按需选择是否在请求url上设置查询参数。更多接口参数请参考《OOS开发者文档-v6》
                  querys.put("response-content-type", "application/octet-stream");
                  String authorization = v2Sign(method, bucket, objectKey, headers, querys);
                  String requestUrl = "http://" + bucket + "." + OOS_ENDPOINT + "/" + urlEncode(objectKey, false);
                  if (querys.size() != 0) {
                      requestUrl += "?" + encodeParameters(querys);
                  }
                  URL url = new URL(requestUrl);
                  HttpURLConnection connection = (HttpURLConnection)url.openConnection();
                  connection.setRequestProperty("Authorization", authorization);
                  connection.setConnectTimeout(CONN_TIMEOUT);
                  connection.setReadTimeout(READ_TIMEOUT);
                  connection.setRequestMethod(method);
                  if (null != headers) {
                      headers.forEach(connection::setRequestProperty);
                  }
                  return connection;
              }
          
              private String encodeParameters(Map<String, String> querys) {
                  StringBuilder builder = new StringBuilder();
                  Iterator<Map.Entry<String, String>> pairs = querys.entrySet().iterator();
                  while (pairs.hasNext()) {
                      Map.Entry<String, String> pair = pairs.next();
                      builder.append(urlEncode(pair.getKey(), false));
                      builder.append("=");
                      builder.append(urlEncode(pair.getValue(), false));
                      if (pairs.hasNext()) {
                          builder.append("&");
                      }
                  }
                  return builder.toString();
              }
          
              // =============== 以下是签名计算相关方法 ===============
              /**
               * The set of request parameters which must be included in the canonical string to sign.
               */
              private static final List<String> SIGNED_PARAMETERS =
                      Arrays.asList("acl", "torrent", "logging", "location", "policy", "requestPayment", "versioning", "versions",
                              "versionId", "notification", "uploadId", "uploads", "partNumber", "website", "delete", "lifecycle",
                              "tagging", "cors", "restore", "response-cache-control", "response-content-disposition",
                              "response-content-encoding", "response-content-language", "response-content-type", "response-expires");
          
              private String v2Sign(String method, String bucket, String objectKey, Map<String, String> headers,
                                    Map<String, String> querys) throws Exception {
                  String canonicalString =
                          getCanonicalString(method, toResourcePath(bucket, objectKey), headers, querys);
                  String signature = sign(canonicalString);
                  return "AWS " + OOS_ACCESS_KEY + ":" + signature;
              }
          
              private String sign(String data) throws Exception {
                  try {
                      Mac mac = Mac.getInstance("HmacSHA1");
                      mac.init(new SecretKeySpec(OOS_SECRET_KEY.getBytes(StandardCharsets.UTF_8), "HmacSHA1"));
                      byte[] bs = mac.doFinal(data.getBytes(StandardCharsets.UTF_8));
                      return Base64.getEncoder().encodeToString(bs);
                  } catch (Exception e) {
                      throw new Exception("Unable to calculate a request signature: " + e.getMessage(), e);
                  }
              }
          
              /**
               * Calculate the canonical string for a REST/HTTP request to OOS.
               *
               * When expires is non-null, it will be used instead of the Date header.
               */
              private String getCanonicalString(String method, String resource, Map<String, String> headers,
                                                Map<String, String> querys) {
                  StringBuilder buf = new StringBuilder();
                  buf.append(method).append("\n");
          
                  SortedMap<String, String> interestingHeaders = new TreeMap<>();
                  if (headers != null && headers.size() > 0) {
                      for (Map.Entry<String, String> entry : headers.entrySet()) {
                          String key = entry.getKey();
                          String value = entry.getValue();
          
                          if (key == null) {
                              continue;
                          }
                          String lk = key.toLowerCase(Locale.getDefault());
          
                          if ("content-type".equals(lk) || "content-md5".equals(lk) || "date".equals(lk)
                                  || lk.startsWith("x-amz-")) {
                              interestingHeaders.put(lk, value);
                          }
                      }
                  }
          
                  // Remove default date timestamp if "x-amz-date" is set.
                  if (interestingHeaders.containsKey("x-amz-date")) {
                      interestingHeaders.put("date", "");
                  }
          
                  // These headers require that we still put a new line in after them,
                  // even if they don't exist.
                  if (!interestingHeaders.containsKey("content-type")) {
                      interestingHeaders.put("content-type", "");
                  }
                  if (!interestingHeaders.containsKey("content-md5")) {
                      interestingHeaders.put("content-md5", "");
                  }
          
                  // Any parameters that are prefixed with "x-amz-" need to be included
                  // in the headers section of the canonical string to sign
                  if (querys != null) {
                      for (Map.Entry<String, String> parameter : querys.entrySet()) {
                          if (parameter.getKey().toLowerCase().startsWith("x-amz-")) {
                              interestingHeaders.put(parameter.getKey().toLowerCase(), parameter.getValue());
                          }
                      }
                  }
          
                  for (Map.Entry<String, String> entry : interestingHeaders.entrySet()) {
                      String key = entry.getKey();
                      Object value = entry.getValue();
          
                      if (key.toLowerCase().startsWith("x-amz-")) {
                          buf.append(key).append(':').append(value);
                      } else {
                          buf.append(value);
                      }
                      buf.append("\n");
                  }
          
                  buf.append(resource);
                  if (querys != null) {
                      String[] parameterNames = querys.keySet().toArray(new String[0]);
                      Arrays.sort(parameterNames);
                      char separator = '?';
                      for (String parameterName : parameterNames) {
                          // Skip any parameters that aren't part of the canonical signed string
                          if (!SIGNED_PARAMETERS.contains(parameterName)) {
                              continue;
                          }
          
                          buf.append(separator);
                          buf.append(parameterName);
                          String parameterValue = querys.get(parameterName);
                          if (parameterValue != null && !"".equals(parameterValue)) {
                              buf.append("=").append(parameterValue);
                          }
                          separator = '&';
                      }
                  }
                  return buf.toString();
              }
          
              private String toResourcePath(String bucket, String objectKey) {
                  String resourcePath =
                          "/" + ((bucket != null && !"".equals(bucket)) ? bucket : "") + ((objectKey != null) ? "/" + objectKey : "");
                  return urlEncode(resourcePath, true);
              }
          
              /**
               * @param keepPathSlash 实际上,根据RFC 3986规范,url中的 '/'和'~' 可以不用转译,URLEncoder做了转译,但是为了兼容浏览器解析文件名,要求 '/'和'~'不能做转译。
               * @param url 客户请求的url,也就是object key
               *
               * @return 转译后的url
               */
              private String urlEncode(String url, boolean keepPathSlash) {
                  String encoded;
                  try {
                      encoded = URLEncoder.encode(url, StandardCharsets.UTF_8.toString());
                  } catch (UnsupportedEncodingException e) {
                      throw new RuntimeException("UTF-8 encoding is not supported.", e);
                  }
          
                  if (keepPathSlash) {
                      // Web browsers do not always handle '+' characters well, use the well-supported '%20' instead.
                      encoded = encoded.replaceAll("\\+", "%20");
                      // Change all "%2F" back to "/", so that when users download a file in a virtual folder by the presigned
                      // URL,
                      // the web browsers won't mess up the filename. (e.g. 'folder1_folder2_filename' instead of 'filename')
                      encoded = encoded.replace("%2F", "/");
                      encoded = encoded.replace("%7E", "~");
                  }
                  return encoded;
              }
          
              public static void main(String[] args) {
                  String bucket = "your bucket";
                  String objectKey = "your object key";
                  OOSDemoForV2Signer v2 = new OOSDemoForV2Signer();
                  v2.putObject(bucket, objectKey);
                  v2.getObject(bucket, objectKey);
                  v2.deleteObject(bucket, objectKey);
              }
          }
          
          
          文档反馈

          建议您登录后反馈,可在建议与反馈里查看问题处理进度

          鼠标选中文档,精准反馈问题

          选中存在疑惑的内容,即可快速反馈问题,我们会跟进处理

          知道了

          上一篇 :  使用HttpURLConnection开发
          下一篇 :  使用V4签名时的HttpURLConnection开发
          搜索 关闭
          ©2025 天翼云科技有限公司版权所有 增值电信业务经营许可证A2.B1.B2-20090001
          公司地址:北京市东城区青龙胡同甲1号、3号2幢2层205-32室
          备案 京公网安备11010802043424号 京ICP备 2021034386号
          ©2025天翼云科技有限公司版权所有
          京ICP备 2021034386号
          备案 京公网安备11010802043424号
          增值电信业务经营许可证A2.B1.B2-20090001
          用户协议 隐私政策 法律声明