使用AliyunCLI进行OSS操作时,相关Content-MD5的说明

最近Support过程中遇到用户使用AliyunCLI这个集大成的工具进行OSS的相关操作,虽然OSS团队强烈建议用户使用OSS内部工具(如osscmd),但是对于购买并使用多种云产品的用户来说,节约学习和维护工具的成本是必要的,使用AliyunCLI来的更为舒服,当然,我们也愿意为亲爱的客户解决一切技术问题。

在介绍用户的使用场景之前,贴个AliyunCLI操作OSS的链接,给大家参考一下。

首先,用户的使用场景是使用AliyunCLI来完成本地文件的上传,在上传的过程中带上Content-MD5,进行文件的完整性校验。从上面的链接可以看出,可以使用如下的命令完成这个需求:

(细心的朋友应该发现,AliyunCLI的Put命令介绍是有问题的,有没有看出来?对,Put后面要跟个"localfile" )

用户使用的命令如下:

aliyuncli oss Put localfile oss://user_bucket_name --header "Content-MD5:userfile_md5" 

结果,不管“userfile_md5”是什么,这个localfile都能上传成功。是不是OSS的md5校验功能不work呢?当然不是哈,细心的朋友应该又发现了,是"--header"这个标签错误了,应该是"--headers",aliyuncli对于错误的标签是不提示错误直接忽略的,所以实际上这里上传的MD5值并没有写入oss请求的头部传入OSS。请千万注意哦~~

接下来,关于Content-MD5值如何生成,我们来详细介绍一下:

关于Content-MD5是啥,OSS官方文档介绍如下。因为HTTP的首部无法记录二进制值,所以需要通过base64编码转化为字符串。在OSS服务端,会使用相同的方法对报文主体进行计算得到对应的值并与报文首部的Content-MD5进行比较,来校验数据的有效性。


 从字面的解释很容易理解,md5值的获取就是两步:
   
 所以,很容易的使用了最方便、现成的shell命令去做这件事了:

知道上面使用md5和base64命令生成的Content-MD5有什么不对么?

MD5 作为校验码,是一个 128 位长的二进制数。 在内存中,128 bits = 16 octets。 经过Base64 编码,长度增加约 33%,编码后的长度应为 4*⌈16/3⌉ = 24 字节。而上图中得到的结果却是44字节?!

这里的确有个坑!!!

我们先来研究一下算法的细节:
HTTP/1.1(RFC2616#14.15)给出了实体首部字段 Content-MD5 的语法规则:

Content-MD5   = "Content-MD5" ":" md5-digest
md5-digest   = <base64 of 128 bit MD5 digest as per RFC 1864>

即校验值的编码依据为 RFC1864:MD5 算法输出的结果为 128 位长的摘要。当以网络字节序(大端序) 解析时,可得到16字节的二进制数据序列。随后,将这 16 个字节按 base64 算法编码,最终得到可作为 `Content-MD5` 字段取值的结果。

在上面的shell命令例子中,我们首先使用md5命令对文件pom.xml的内容进行了MD5算法,得到一个128bit的二进制数,可以表示为0xOGI4NWYzYWZkNWY2OTRmMzQzMmM5YzQ5YWM1N2Q3ZGYK。然后使用base64进行了编码得出最后结果,这里到底哪儿有坑呢?
坑在于:错误的base64进行编码的不是对0xOGI4NWYzYWZkNWY2OTRmMzQzMmM5YzQ5YWM1N2Q3ZGYK这个数值,而是对"OGI4NWYzYWZkNWY2OTRmMzQzMmM5YzQ5YWM1N2Q3ZGYK"这串字符串!!

      这里,强调一下,是对128bit进行编码哦!附一段计算文件的Content-MD5的脚本给大家参考一下:

#-*-coding:utf-8-*-
#!/bin/env python

import md5
import sys
import base64

def md5file(fobj):
    m = md5.new()
    while True:
        d = fobj.read(8096)
        if not d:
            break
        m.update(d)
    return (str)(base64.b64encode(m.digest()))

if __name__ == '__main__':
    fname = sys.argv[1]
    f = file(fname, 'rb')
    print '%s' % (md5file(f))
    f.close()

 

---------------------------------------分割线---------------------------------------------------

诚聘英才

阿里云函数服务是一个全新的,支持事件驱动编程模式的计算服务。 他帮助用户聚焦自身业务逻辑,以Serverless的方式构建应用,快速的实现低成本,可扩展,高可用的系统,而无需考虑服务器等底层基础设施的管理。 用户能够快速的创建原型,同样的架构能随业务规模平滑伸缩。让计算变得更高效,更经济,更弹性,更可靠。无论小型创业公司,还是大型企业,都受益其中。

我们的团队正在迅速扩张,求贤若渴。我们想寻找这样的队友:

  • 基本功扎实。既能阅读论文追踪业界趋势,又能快速编码解决实际问题。
  • 严谨的,系统化的思维能力。既能整体考虑业务机会,系统架构,运维成本等诸多因素,又能掌控设计/开发/测试/发布的完整流程,预判并控制风险。
  • 好奇心和使命感驱动。乐于探索未知领域,不仅是梦想家,也是践行者。
  • 坚韧、乐观、自信。能在压力和困难中看到机会,让工作充满乐趣!

如果您对云计算充满热情,想要构建一个有影响力计算平台和生态体系,请加入我们,和我们一起实现梦想! 

详见:http://www.atatech.org/articles/53851

将你的简历发送到shuting.yst@alibaba-inc.com,标题  应聘阿里云-姓名

如果你有自己的git地址或者个人博客,将会大大加分哦,一起在邮件中发给我吧~~~

时间: 2025-01-02 14:12:53

使用AliyunCLI进行OSS操作时,相关Content-MD5的说明的相关文章

【OSS 最佳实践】OSS 操作权限控制

用户操作 OSS 时是需要根据账号的 AccessKeyId 和 AccessKeySecret (后续简称 AK 和 SK )进行权限验证的,这里的 AK 和 SK 包括有多种类型:主账号的 AK 和 SK .子账号的 AK 和 SK 以及 STS 生成的临时 AK . SK 和 Token .那么他们之间有什么区别呢?具体应该如何配置使用呢?本文将带大家一起认识相关概念. 1. 概念区别 主账号的 AK 和 SK 是主账号对应的权限标识,也就是说主账号的每对 AK和 SK 是拥有账号下的所有

string-执行搜索操作时字符串索引的绑定异常

问题描述 执行搜索操作时字符串索引的绑定异常 我在获取联系人后执行一个搜索操作,当我在搜索栏中快速输入字母时显示下面的异常,程序也奔溃了.如何解决这个问题呢? @Overridepublic boolean onQueryTextChange(String newtext) { String searchString = newtext; int textLength = searchString.length(); ArrayList<Masterlistmodel> type_name_f

游标操作时进行Update应注意的一个问题

问题|游标 在进行游标操作时,如果你使用了Order by 子句,但Order by 的字段没有索引, 则会导至游标为只读属性, 并且不能指定为for Update状态. 解决办法:去掉Order by 子句或者对Order by的字段进行索引.

Win7远程操作时提示“远程桌面服务当前正忙”两种解决方法

  Win7远程操作时提示"远程桌面服务当前正忙"两种解决方法           Win7系统远程桌面操作能够实现远程操控电脑,通过远程连接来进行一些控制,可是有些用户在进行远程连接的时候,输入账号密码无法进入,重新进入就会提示"由于远程桌面服务当前正忙,因此无法完成您尝试执行的任务",遇到这个问题该如何解决呢?下面小编给大家两种解决方法. 解决方法一 看一下你电脑任务管理器此项任务是否还在,如果在的话关掉就行了,很多时候是电脑没有反应过来造成的. 解决办法二 原

在hadoop进行 randomwriter -clean操作时,出现如下异常

问题描述 在hadoop进行 randomwriter -clean操作时,出现如下异常 ubuntu@master:~$ hadoop-2.5.2/bin/hadoop jar hadoop-2.5.2/share/hadoop/mapreduce/hadoop-mapreduce-examples-2.5.2.jar randomwriter -clean 15/10/10 09:11:02 INFO mapreduce.Job: Task Id : attempt_144443828477

qt-QT 怎么知道数据库操作时哪里错了

问题描述 QT 怎么知道数据库操作时哪里错了 QT 怎么知道数据库操作时哪里错了,怎么捕捉错误QT 怎么知道数据库操作时哪里错了,怎么捕捉错误 解决方案 sql.exex()执行后如果有错输出sql.lasterror可以查看出错信息 解决方案二: CSDN的问题为什么这么简洁?1. 使用的什么数据库接口? 2. qt自己的driver还是其他的库?3. 是什么错呢?程序错误?库错误?网络错误?还是sql语法错误?把错误信息贴出来. 描述清楚一点,方便帮你解答.

ios-multi touches:多手势操作时anchorpoint的计算问题

问题描述 multi touches:多手势操作时anchorpoint的计算问题 ios代码中添加一个旋转的收拾识别UIRotationGestureRecognizer功能,在对应的target方法中如果加入一下代码: if (gestureRecognizer.state == UIGestureRecognizerStateBegan) { UIView *piece = gestureRecognizer.view; CGPoint locationInView = [gestureR

nand操作时page_size = 2048;

问题描述 nand操作时page_size = 2048; 您好,我想咨询一下,page_size = 2048; 这个是指的什么啊?页的大小是不是都是512的大小啊?还有就是nandll_read_page函数,copy2ddr函数的含义可以解释一下吗? 解决方案 不同存储容量page size 是不一样的.2048正常啊,还有256的 解决方案二: 要结合具体的代码来看

sqlserver2008触发器-SQL触发器进行更新操作时 用insert添加发生主键冲突

问题描述 SQL触发器进行更新操作时 用insert添加发生主键冲突 环境:SQLserver 2008 创建的表 --库存表(还有多少商品)ID 名称 库存数量 --销售表(卖了多少商品)ID 销售数量 create table StockInfo ( ProID int primary key identity(1,1), ProName nvarchar(20) not null, ProNumber int not null ) go create table SellTab--销售表