OSS 实践篇-OSS C SDK 深度案例

本文涉及的产品
对象存储 OSS,20GB 3个月
.cn 域名,1个 12个月
日志服务 SLS,月写入数据量 50GB 1个月
简介: 概述:客户使用 OSS C SDK 3.5 版本,通过 get_object_to_local_file 方法直接下载 OSS文件到本地,测试过程返回 403 签名不对;搜集信息挖取有价值的信息很重要,通过基础信息可以筛选下客户上传日志的详细描述,通过堆栈报错可以找到客户大概原因;OSS...

概述:

客户使用 OSS C SDK 3.5 版本,通过 get_object_to_local_file 方法直接下载 OSS文件到本地,测试过程返回 403 签名不对;

搜集信息

挖取有价值的信息很重要,通过基础信息可以筛选下客户上传日志的详细描述,通过堆栈报错可以找到客户大概原因;

  • OSS response header 中包含 requestID ,记录客户端请求到 OSS 的详细日志;
  • 堆栈完整报错信息;

分析 requestID 对应的服务端错误日志

服务端返回 4xx 2xx 3xx 500 的状态码都会返回 requestID;通过 requestID 我们可以过滤到服务的错误日志如下;

java
Method:HEAD    Host:oss-cn-shanghai.aliyuncs.com    URI:/vod%2Fplat%2Fupdate%2Fhaimu_21_9%2FBasketball.zip

StringToSign:HEAD\n\n\nWed, 06 Nov 2019 07:55:44 GMT\n/vod/plat/update/haimu_21_9/Basketball.zip
UserSignature:LIMmOQ/5TLs2Gk24MuNVRl+Lu0Q=    OssServerSignature:P+YZauMD+fRtZjeMWkauuN6A4eU=

ErrorCode:SignatureDoesNotMatch    ErrorMsg:The request signature we calculated does not match the signature you provided. Check your key and signing method.

image

  • 通过日志可以明显看出客户端签名和服务端签名不一致导致校验失败;
  • 根据签名算法可以知道这算计算签名的参数中 /vod/plat/update/haimu_21_9/Basketball.zip 其中 vod 是 bucket 的位置;
  • Host: oss-cn-shanghai.aliyuncs.com 这个位置是错误,因为正常的直接访问 OSS ,Host 正确写法应该是 bucket.oss-cn-region.aliyuncs.com(region 替换成 bucket 所在地区)

问题分析

线索一

已经知道问题出现在签名不对,而且 Host 也不对;问题出现在这里,但是如果 Host ,但 OSS 还能识别出 bucket ,这很奇怪;于是和用户沟通, vod 并不是用户的 bucket,那这个桶是怎么获取到的呢?遂让用户在端上进行 Wireshark 抓包, 得到报文

image

  1. 从报文中可以看到 Host 是客户端传的时候就没有 bucket ;
  2. 而 vod 是用户 objectkey 文件前缀而已;
  3. 通过上述几点可以知道问题一定是用户代码上哪里出现的变量写错或者用法不对;

线索二

请用户在本地 debug ,将关键签名的变量信息打印出来看是否完整;

关键信息位置

image

用户自己 debug 出来变量的位置

image

通过客户 debug 看到变量都正确,为什么还会出现 bucket “丢失” 的情况呢;

线索三

分析源码

int get_object_to_local_file(char *bucketname, char *objectname, char *filename)
{
    aos_pool_t *p = NULL;
    aos_string_t bucket;
    aos_string_t object;
    oss_request_options_t *options = NULL;
    aos_table_t *headers = NULL;
    aos_table_t *params = NULL;
    aos_table_t *resp_headers = NULL;
    aos_status_t *s = NULL;
    aos_string_t file;
    int is_cname = 1;

    if (bucketname == NULL || objectname == NULL || filename == NULL)
        return -1;

    aos_pool_create(&p, NULL);
    options = oss_request_options_create(p);
    init_sample_request_options(options, is_cname);
    aos_str_set(&bucket, bucketname);
    aos_str_set(&object, objectname);
    headers = aos_table_make(p, 0);
    aos_str_set(&file, filename);

    s = oss_get_object_to_file(options, &bucket, &object, headers,
        params, &file, &resp_headers);
    if (aos_status_is_ok(s))
    {
        printf("get object to local file succeeded\n");
    }
    else
    {
        printf("get object to local file failed\n");
        aos_pool_destroy(p);
        return -2;
    }
    aos_pool_destroy(p);
    return 0;
}

— —> 从源码中可以,getobject 下载时形参都是传进来的,既然客户 debug 的变量都是正确的,那么肯定不是传进来变量 ,问题一定是方法内的常量导致;对比官方源码:

void get_object_to_local_file()
{
    aos_pool_t *p = NULL;
    aos_string_t bucket;
    char *download_filename = "get_object_to_local_file.txt";
    aos_string_t object;
    int is_cname = 0;
    oss_request_options_t *options = NULL;
    aos_table_t *headers = NULL;
    aos_table_t *params = NULL;
    aos_table_t *resp_headers = NULL;
    aos_status_t *s = NULL;
    aos_string_t file;

    aos_pool_create(&p, NULL);
    options = oss_request_options_create(p);
    init_sample_request_options(options, is_cname);
    aos_str_set(&bucket, BUCKET_NAME);
    aos_str_set(&object, OBJECT_NAME);
    headers = aos_table_make(p, 0);
    aos_str_set(&file, download_filename);

    s = oss_get_object_to_file(options, &bucket, &object, headers, 
                               params, &file, &resp_headers);
    if (aos_status_is_ok(s)) {
        printf("get object to local file succeeded\n");
    } else {
        printf("get object to local file failed\n");
    }

    aos_pool_destroy(p);
}

— —> 从源码和用户的源码对比发现有个 cname 的参数,这个参数用户端是 1,官网的源码是 0,参数的含义,是否启用 cname 方式上传, cname 简称别名,比如用户给 bucket 绑定一个备案的域名后,那个域名就是 cname;我们追下 cname 的用法。

    if (options->config->is_cname ||
        is_valid_ip(raw_endpoint_str))
    {
        req->host = apr_psprintf(options->pool, "%.*s",
                raw_endpoint.len, raw_endpoint.data);
        req->uri = apr_psprintf(options->pool, "%.*s", bucket->len,
                                bucket->data);
    } else {
        req->host = apr_psprintf(options->pool, "%.*s.%.*s",
                bucket->len, bucket->data,
                raw_endpoint.len, raw_endpoint.data);
        req->uri = apr_psprintf(options->pool, "%s", "");
    }

— —> 从这端代码中可以看到,启用了 cname 后,Host 直接取的 endpoint 值;基本上找到了和用户用了 cname 有关系;

  • 经过后台分析发现用户端并没有绑定 oss+域名 的映射关系,而 SDK 在启动了 cname 上传,把 endpoint 当做完成的域名,没有把用户的 bucket name 拼到 Host 中,认为启用 cname 后, endpoint 就是完成域名;(设计就是这样并不是缺陷)
  • 让用户把 cname 改为 0 ,采用直接的方式,这样 SDK 会把 bucketname 和 endpoint 拼成一个 完成域名再上传;

总结

该问题核心在于

1、要对 OSS SDK 的用法熟悉,知道如何进行本地对比用户测试;

2、要清楚排查思路知道搜集哪些有价值的信息;

3、层级递进,从签名算法着眼,推测到是代码中的使用;

4、善用 tcpdump/wireshark 抓包分析请求报文;

相关实践学习
借助OSS搭建在线教育视频课程分享网站
本教程介绍如何基于云服务器ECS和对象存储OSS,搭建一个在线教育视频课程分享网站。
目录
相关文章
|
1月前
|
存储 人工智能 开发工具
AI助理化繁为简,速取代码参数——使用python SDK 处理OSS存储的图片
只需要通过向AI助理提问的方式输入您的需求,即可瞬间获得核心流程代码及参数,缩短学习路径、提升开发效率。
1433 4
AI助理化繁为简,速取代码参数——使用python SDK 处理OSS存储的图片
|
4月前
|
消息中间件 分布式计算 DataWorks
DataWorks产品使用合集之如何使用Python和阿里云SDK读取OSS中的文件
DataWorks作为一站式的数据开发与治理平台,提供了从数据采集、清洗、开发、调度、服务化、质量监控到安全管理的全套解决方案,帮助企业构建高效、规范、安全的大数据处理体系。以下是对DataWorks产品使用合集的概述,涵盖数据处理的各个环节。
|
6月前
|
存储 数据管理 Java
基于OSS、NFS构建高性能可扩展的遥感智能解译系统实践之路
该文探讨了构建高性能、可扩展的遥感智能解译系统的架构演进过程。作者强调架构应根据业务场景而定,而非追求单一的“最佳”架构。文章分为五个部分,介绍了从初步的业务场景分析到逐步优化的架构设计。 1. 业务场景描述了服务于地理信息行业的遥感数据管理平台,包括数据湖和遥感智能解译系统的功能和架构设计。 2. 初代系统解决了数据管理和智能解译的基本需求,但存在数据同步效率低下的问题。 3. 自动化阶段通过消息推送和数据接收模块减少了人工干预,将处理时间减半,但仍存在效率和稳定性问题。 4. 高性能阶段引入数据订阅/推送和数据接收Agent,实现了稳定、高速的数据传输,性能提升了6倍。
48834 2
|
6月前
|
安全 Go 开发工具
对象存储OSS产品常见问题之go语言SDK client 和 bucket 并发安全如何解决
对象存储OSS是基于互联网的数据存储服务模式,让用户可以安全、可靠地存储大量非结构化数据,如图片、音频、视频、文档等任意类型文件,并通过简单的基于HTTP/HTTPS协议的RESTful API接口进行访问和管理。本帖梳理了用户在实际使用中可能遇到的各种常见问题,涵盖了基础操作、性能优化、安全设置、费用管理、数据备份与恢复、跨区域同步、API接口调用等多个方面。
145 9
|
3月前
|
JavaScript 前端开发 Java
[Android][Framework]系统jar包,sdk的制作及引用
[Android][Framework]系统jar包,sdk的制作及引用
91 0
|
17天前
|
Java Linux API
Android SDK
【10月更文挑战第21天】
48 1
|
27天前
|
程序员 开发工具 Android开发
Android|使用阿里云推流 SDK 实现双路推流不同画面
本文记录了一种使用没有原生支持多路推流的阿里云推流 Android SDK,实现同时推送两路不同画面的流的方法。
47 7
|
3月前
|
开发工具 Android开发
解决Android运行出现NDK at /Library/Android/sdk/ndk-bundle did not have a source.properties file
解决Android运行出现NDK at /Library/Android/sdk/ndk-bundle did not have a source.properties file
168 4
解决Android运行出现NDK at /Library/Android/sdk/ndk-bundle did not have a source.properties file
|
3月前
|
Dart 开发工具 Android开发
Android Studio导入Flutter项目提示Dart SDK is not configured
Android Studio导入Flutter项目提示Dart SDK is not configured
317 4
|
3月前
|
开发工具 Android开发
Flutter: Android SDK not found at this location,Android Studio not found at xxx
Flutter: Android SDK not found at this location,Android Studio not found at xxx
159 2

热门文章

最新文章