利用Wireshark和OSS的API文档简单实现上传和下载

背景及目的

由于各个开发者使用的开发语言可能在官方SDK找不到相应的语言版本,就必须自主开发SDK。
本文根据wireshark和API文档,来简单实现上传和下载的请求,给需要自主开发的开发者提供一个简单的示例。

准备工作

安装wireshark

官网地址:https://www.wireshark.org/download.html
找到合适的平台及版本,下载并安装。

找到OSS的API文档

官网地址:https://help.aliyun.com/document_detail/oss/api-reference/abstract.html

准备开发环境

1. 这里使用的是python 2.7, 并且使用requests库。

http://cn.python-requests.org/zh_CN/latest/

2. 需要开通OSS,并且拥有一个bucket,同时需要获取AccessKeyId和AccessKeySecret

实践

基于OSS API文档,用python实现一个简单的上传和下载操作

上传

1. 先看Put Object的API文档

https://help.aliyun.com/document_detail/oss/api-reference/object/PutObject.html

请求语法
PUT /ObjectName HTTP/1.1
Content-Length:ContentLength
Content-Type: ContentType
Host: BucketName.oss-cn-hangzhou.aliyuncs.com
Date: GMT Date
Authorization: SignatureValue

2. 构建类似的HTTP请求

BucketName是ali-beijing
Endpoint是oss-cn-beijing.aliyuncs.com
ObjectName是test.txt
将如下的代码保持文件后运行

import requests
bucket = "ali-beijing"
objectname = "test.txt"
endpoint = "oss-cn-beijing.aliyuncs.com"
url = "http://%s.%s/%s" % (bucket, endpoint, objectname)
headers = {}
r = requests.put(url, data="hello", headers=headers)
print r.text
print r.status_code
print r.headers

3. 运行的同时,打开wireshark来抓包,查看请求

运行完毕后,停止抓包,查看请求。
如图所示:

停止抓包后点击图中红框的"Protocol",找到发送的HTTP请求,然后点击“Analyze"->"Follow TCP Stream",即可看到整个HTTP请求的内容。

可以看到最终的HTTP请求如下所示

PUT /test.txt HTTP/1.1
Host: ali-beijing.oss-cn-beijing.aliyuncs.com
Content-Length: 5
User-Agent: python-requests/2.5.1 CPython/2.7.10 Darwin/15.0.0
Connection: keep-alive
Accept: /
Accept-Encoding: gzip, deflate

hello

HTTP/1.1 403 Forbidden
Server: AliyunOSS
Date: Tue, 26 Apr 2016 10:01:20 GMT
Content-Type: application/xml
Content-Length: 279
Connection: keep-alive
x-oss-request-id: 571F3C704FF4F07A6A0080A6

<?xml version="1.0" encoding="UTF-8"?>
<Error>
  <Code>AccessDenied</Code>
  <Message>You have no right to access this object because of bucket acl.</Message>
  <RequestId>571F3C704FF4F07A6A0080A6</RequestId>
  <HostId>ali-beijing.oss-cn-beijing.aliyuncs.com</HostId>
</Error>

经过和Put Object的协议对比,我们可以看到,请求的header中没有加入Authorization,以及Date,也没有Content-Type。由于bucket是私有权限,没有Authorization的认证信息是无法对bucket进行写入操作。所以需要加入签名信息。

4. 根据API文档描述的,加入签名的信息

签名相关的文档见:
https://help.aliyun.com/document_detail/oss/api-reference/access-control/signature-header.html

#coding=utf-8
import requests, datetime, hmac, httplib, hashlib
from email.utils import formatdate
from urllib import quote
from base64 import b64encode

class OssRequest():
    def __init__(self,  endpoint, AccessKeyId, AccessKeySecret, bucket):
        self.endpoint = endpoint
        self.AccessKeyId = AccessKeyId
        self.AccessKeySecret = AccessKeySecret
        self.bucket = bucket
        self.objectname = ""
        self.subresource = ""
        self.VERB = ""

    def format_oss_headers(self, headers=None):
        map = {}
        for header, value in headers.iteritems():
            header = header.lower()
            if header.startswith("x-oss-"):
                map.setdefault(header, []).append(value)
        parts = []
        for key in sorted(map):
            parts.append("%s:%s\n" % (key, ",".join(map[key])))
        return "".join(parts)

    def canonical_resource(self):
        resource = "/"
        if self.bucket:
            resource += self.bucket + "/"
        if self.objectname:
            resource += "%s" % self.objectname
        if self.subresource:
            resource += "?%s" % quote(self.subresource, "/")
        return resource

    def sign(self, headers=None):
        if not headers:
            headers = {}
        AuthString = "\n".join(str(item_) for item_ in items) + "\n"
        CanonicalizedOSSHeaders = self.format_oss_headers(headers)
        CanonicalizedResource = self.canonical_resource()
        AuthString = "".join((AuthString, CanonicalizedOSSHeaders, CanonicalizedResource))
        Signature = '%s' % (b64encode(hmac.new(AccessKeySecret, AuthString.encode("utf-8"), hashlib.sha1).digest()))
        return Signature

    def put(self, objectname):
        self.VERB = 'PUT'
        self.objectname = objectname
        url = "http://%s.%s/%s" % (self.bucket, self.endpoint, self.objectname)
        headers = {'Date' : formatdate(None, usegmt=True)}
        Signature = self.sign(headers)
        headers['Authorization'] = 'OSS %s:%s' % (self.AccessKeyId, Signature)
        r = requests.put(url, data = "hello", headers=headers)
        print r.text
        print r.status_code
        print r.headers

if name == "__main__":
    AccessKeyId = "替换成自己的AccessKeyId"
    AccessKeySecret = "替换成自己的AccessKeySecret"
    bucket = "ali-beijing"
    objectname = "test.txt"
    endpoint = "oss-cn-beijing.aliyuncs.com"
    a = OssRequest(endpoint, AccessKeyId, AccessKeySecret, bucket)
    a.put(objectname)

5. 再次在运行后,通过wireshark抓包观察

同之前的抓包和观察方法,可以看到,上传成功了。

PUT /test.txt HTTP/1.1
Host: ali-beijing.oss-cn-beijing.aliyuncs.com
Content-Length: 5
Accept-Encoding: gzip, deflate
Accept: /
User-Agent: python-requests/2.5.1 CPython/2.7.10 Darwin/15.0.0
Connection: keep-alive
Date: Tue, 26 Apr 2016 13:44:42 GMT
Content-Type: plain/text
Authorization: OSS testaliyun:1aUnxjJ4V/0+pTwzd7t9An3d10c=

helloHTTP/1.1 200 OK
Server: AliyunOSS
Date: Tue, 26 Apr 2016 13:44:42 GMT
Content-Length: 0
Connection: keep-alive
x-oss-request-id: 571F70CA4FF4F07A6A022212
ETag: "5D41402ABC4B2A76B9719D911017C592"
x-oss-hash-crc64ecma: 11177612005948864433

下载

1. 查看Get Object的API文档

https://help.aliyun.com/document_detail/oss/api-reference/object/GetObject.html

GET /ObjectName HTTP/1.1
Host: BucketName.oss-cn-hangzhou.aliyuncs.com
Date: GMT Date
Authorization: SignatureValue
Range: bytes=ByteRange(可选)

2. 在上传成功的基础上实现下载

由于之前上传Object已经成功,这里只需要添加如下代码

省略和上传一样的代码
在def put(self, objectname):
函数下添加

    def get(self, objectname):
        self.VERB = 'GET'
        self.objectname = objectname
        url = "http://%s.%s/%s" % (self.bucket, self.endpoint, self.objectname)
        headers = {'Date' : formatdate(None, usegmt=True)}
        Signature = self.sign(headers)
        headers['Authorization'] = 'OSS %s:%s' % (self.AccessKeyId, Signature)
        r = requests.get(url, headers=headers)
        print r.text
        print r.status_code
        print r.headers

调用的时候在a.put(objectname)下添加a.get(objectname)

3. 抓包观察

GET /test.txt HTTP/1.1
Host: ali-beijing.oss-cn-beijing.aliyuncs.com
Accept-Encoding: gzip, deflate
Accept: /
User-Agent: python-requests/2.5.1 CPython/2.7.10 Darwin/15.0.0
Connection: keep-alive
Date: Tue, 26 Apr 2016 14:16:32 GMT
Authorization: OSS testaliyun:ARRfi3zGoiGdrAjmM5lJ0o4LEBA=

HTTP/1.1 200 OK
Server: AliyunOSS
Date: Tue, 26 Apr 2016 14:16:32 GMT
Content-Type: plain/text
Content-Length: 5
Connection: keep-alive
x-oss-request-id: 571F78404FF4F07A6A023023
Accept-Ranges: bytes
ETag: "5D41402ABC4B2A76B9719D911017C592"
Last-Modified: Tue, 26 Apr 2016 13:44:42 GMT
x-oss-object-type: Normal
x-oss-hash-crc64ecma: 11177612005948864433
Cache-Control: max-age=86400

hello

以上是根据API文档,简单实现的上传和下载操作。
代码都是很简单的,没有异常的重试,也没有考虑大文件的上传和下载。
主要目的是演示如何通过wireshark和API文档来构建HTTP 请求来实现OSS的相关接口。

常见问题

1. Content-MD5计算错误

以消息内容为"123456789"来说,计算这个字符串的Content-MD5

正确的计算方式:
标准中定义的算法简单点说就是:
1. 先计算MD5加密的二进制数组(128位)。
2. 再对这个二进制进行base64编码(而不是对32位字符串编码)。 

以Python为例子:
正确计算的代码为:
>>> import base64,hashlib
>>> hash = hashlib.md5()
>>> hash.update("0123456789")
>>> base64.b64encode(hash.digest())
'eB5eJF1ptWaXm4bijSPyxw=='

需要注意
正确的是:hash.digest(),计算出进制数组(128位)
>>> hash.digest()
'x\x1e^$]i\xb5f\x97\x9b\x86\xe2\x8d#\xf2\xc7'

常见错误是直接对计算出的32位字符串编码进行base64编码。
例如,错误的是:hash.hexdigest(),计算得到可见的32位字符串编码
>>> hash.hexdigest()
'781e5e245d69b566979b86e28d23f2c7'
错误的MD5值进行base64编码后的结果:
>>> base64.b64encode(hash.hexdigest())
'NzgxZTVlMjQ1ZDY5YjU2Njk3OWI4NmUyOGQyM2YyYzc='

2. 某些头部没有加入到签名的计算中

例如x-oss-开头的header没有加入到签名的计算中。

3. Content-Type设置不对

上传Objec的时候没有设置正确的Content-Type,导致浏览器等无法根据Content-Type进行预览等处理。

时间: 2024-10-27 14:20:01

利用Wireshark和OSS的API文档简单实现上传和下载的相关文章

[sharepoint]rest api文档库文件上传,下载,拷贝,剪切,删除文件,创建文件夹,修改文件夹属性,删除文件夹,获取文档列表

写在前面 最近对文档库的知识点进行了整理,也就有了这篇文章,当时查找这些接口,并用在实践中,确实废了一些功夫,也为了让更多的人走更少的弯路. 系列文章 sharepoint环境安装过程中几点需要注意的地方 Rest API的简单应用 rest api方式实现对文档库的管理 通过WebClient模拟post上传文件到服务器 WebHttpRequest在sharepoint文档库中的使用 [sharepoint]Rest api相关知识(转) [sharepoint]根据用户名获取该用户的权限

谷歌文档支持文件上传GDriver初现端倪

北京时间1月13日下午消息,据国外媒体报道,谷歌周三称,用户将能上传各种类文件到Google Docs(谷歌文档)账户中,上传文件最大可达250M.此举是谷歌为推出网络硬盘类业务做出的最新努力. 谷歌表示,这一服务可以让用户更轻松地通过网络存取文件,甚至可以放弃U盘,并能更方便地实现文件共享. Google Docs产品经理维贾伊·班加鲁(Vijay Bangaru)在博客中写道:"这一功能还能在开发中,帮助你实现在线的信息组织和协作工作.譬如,建筑师能够将设计图纸发送到建筑公司,学生报的编辑可

使用oss c sdk自定义上传和下载callback

       前段时间使用阿里云官网提供的OSS C SDK上传和下载数据,想在上传和下载过程中对数据进行一些简单的自定义预处理,看了一下oss c sdk的具体实现,大致了解如何通过自定义上传和下载的callback达到上述目的,这里做一个简单的分享.        OSS C SDK在上传和下载数据时使用了CURL进行通信,之前简单学习过CURL的一些知识,知道CURL提供了一系列Callback,在上传下载时对数据进行一些处理,大家感兴趣的话可以参考: http://curl.haxx.s

Clojure世界:API文档生成

    继续Clojure世界之旅,介绍下我今天的探索成果,使用clojure生成clojure项目的API文档.在java里,我们是利用javadoc生成API文档,各种build工具都提供了集成,例如maven和ant都提供了javadoc插件或者task.在Clojure世界里,同样有一系列工具帮助你从源码中自动化生成API文档.今天主要介绍三个工具.不过我不会介绍怎么在clojure里写doc,具体怎么做请看一些开源项目,或者直接看clojure.core的源码.     首先是codo

在项目中利用TX Text Control进行WORD文档的编辑显示处理

在很多文档管理的功能模块里面,我们往往需要对WORD稳定进行展示.编辑等处理,而如果使用微软word控件进行处理,需要安装WORD组件,而且接口使用也不见得简单易用,因此如果有第三方且不用安装Office的能够展示WORD及进行编辑,那是比较不错的选择,TX Text Control就是这样的控件,本文就是基于这个控件的使用,实现在文档管理项目中的应用. 1.TX Text Control的介绍及使用 TX Text Control是一款功能类似于 MS Word 的文字处理控件,包括文档创建.

YUIDoc example代码高亮错误、生成API文档目录不按源文件注释顺序

1.如果发现yuidoc命令用不了,那就重装nodejs吧    昨天不知道是清扫电脑的原因,yuidoc命令用不了(命令不存在),也没有找到好的解决方法,怒重装YUIDoc也不行.最后想了想,怒重装了nodejs,再装回YUIDoc,发现又可以了,原因还没找到. 2.YUIDoc的theme中的simple模板,sidebar.handlebar有写错.    里面属性遍历的properties被写成了events 3.YUIDoc example代码高亮错误的解决方法   使用过YUIDoc

利用XSL和ASP实现XML文档在线编辑

xml|在线 本文通过一个详细的例子,来阐述了在线编辑XML文档数据的方法.由于Netscape对XML的支持比较弱,因此,要实现跨平台的数据交换,数据的处理必须在服务器端进行.要编辑XML文档,首先要做的事情就是怎样把这些数据提取并显示给访问者,XSL为我们显示XML文件提供了一个很好的解决方案.下面的例子就是利用XSL样式单把XML文档显示出来,供用户进行编辑,然后再把编辑后的数据提交到服务器,在服务器端进行数据的更新.这里采用ASP(Active Server Pages)来完成我们的任务

利用ASP.NET来访问Excel文档

asp.net|excel|访问|来访 利用ASP.NET来访问Excel文档 Excel是Microsoft公司的Office套件中的一种软件,他主要用来处理电子表格.Excel以界面友好.处理数据迅速等优点获得广大办公人员的欢迎.所以很多文档就以Excel的形式保存了下来.对于程序设计人员,在程序设计中,我们往往要访问Excel文件来获得数据.但由于Excel文件不是标准数据库,所以用程序语言来访问他就比较困难. ASP.NET是Microsoft公司极力推荐的一个产品,作为.NET Fra

Qt学习之路(6):API文档的使用

今天来说一下有关Qt API文档的使用.因为Qt有一个商业版本,因此它的文档十分健全,而且编写良好.对于开发者来说,查看文档时开发必修课之一--没有人能够记住那么多API的使用! 在Qt中查看文档是一件很简单的事情.如果你使用QtCreator,那么左侧的Help按钮就是文档查看入口.否则的话,你可以在Qt的安装目录下的bin里面的assistant.exe中看到Qt的文档.在早期版本中,Qt的文档曾以HTML格式发布,不过在2009.03版中我没有找到 HTML格式的文档,可能Qt已经把它全部