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

本文涉及的产品
对象存储 OSS,20GB 3个月
对象存储 OSS,恶意文件检测 1000次 1年
对象存储 OSS,内容安全 1000次 1年
简介:

背景及目的

由于各个开发者使用的开发语言可能在官方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来抓包,查看请求

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

停止抓包后点击图中红框的"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进行预览等处理。

相关实践学习
借助OSS搭建在线教育视频课程分享网站
本教程介绍如何基于云服务器ECS和对象存储OSS,搭建一个在线教育视频课程分享网站。
目录
相关文章
|
1月前
|
Java API 开发工具
如何用阿里云 oss 下载文件
阿里云对象存储服务(OSS)提供了多种方式下载文件,以下讲解下各种方式的下载方法
759 1
|
1月前
|
数据可视化 Linux API
如何在Linux使用docker部署Swagger Editor并实现无公网IP远程协同编辑API文档
如何在Linux使用docker部署Swagger Editor并实现无公网IP远程协同编辑API文档
|
2月前
|
分布式计算 API Linux
通义千问API:找出两篇文章的不同
本章我们将介绍如何利用大模型开发一个文档比对小工具,我们将用这个工具来给互联网上两篇内容相近但版本不同的文档找找茬,并且我们提供了一种批处理文档比对的方案
|
2月前
|
数据可视化 API 开发者
通俗易懂:一步步教你 Flask 项目自动生成 API 文档
Flasgger,作为一款强大的 Flask 扩展,自动从 Flask 应用中提取并生成 OpenAPI 规范文档,配备 SwaggerUI,为开发者提供了一条快捷通道,让 API 的文档编制和交互式测试变得简单易行。Flasgger 的设计原则是简化开发流程,通过与 Flask 框架的无缝整合,让开发者可以更专注于应用逻辑的构建。
|
2月前
|
API
Poi 中文API文档 「40种操作 Excel文件的姿势」
Poi 中文API文档 「40种操作 Excel文件的姿势」
116 0
|
3月前
|
JSON API 数据格式
您可以在钉钉开放平台的API文档中找到对应的API接口来创建审批实例
您可以在钉钉开放平台的API文档中找到对应的API接口来创建审批实例【1月更文挑战第20天】【1月更文挑战第96篇】
43 2
|
3月前
|
存储 安全 API
利用对象存储(OSS)实现内容分发加速 :高效可靠的解决跨境下载延迟问题
利用对象存储(OSS)实现内容分发加速 :高效可靠的解决跨境下载延迟问题
85 2
|
3天前
|
Java API 对象存储
对象存储OSS产品常见问题之使用Spring Cloud Alibaba情况下文档添加水印如何解决
对象存储OSS是基于互联网的数据存储服务模式,让用户可以安全、可靠地存储大量非结构化数据,如图片、音频、视频、文档等任意类型文件,并通过简单的基于HTTP/HTTPS协议的RESTful API接口进行访问和管理。本帖梳理了用户在实际使用中可能遇到的各种常见问题,涵盖了基础操作、性能优化、安全设置、费用管理、数据备份与恢复、跨区域同步、API接口调用等多个方面。
22 2
|
3天前
|
存储 移动开发 前端开发
对象存储oss使用问题之OSS SDK .net 使用下载例程报错如何解决
《对象存储OSS操作报错合集》精选了用户在使用阿里云对象存储服务(OSS)过程中出现的各种常见及疑难报错情况,包括但不限于权限问题、上传下载异常、Bucket配置错误、网络连接问题、跨域资源共享(CORS)设定错误、数据一致性问题以及API调用失败等场景。为用户降低故障排查时间,确保OSS服务的稳定运行与高效利用。
19 0
|
25天前
|
存储 API 开发工具
oss数据解密与下载
阿里云OSS提供服务器端加密(SSE-OSS/SSE-KMS)功能,保证静态数据安全。下载加密对象时,OSS自动解密并返回原始内容。确保下载请求者有相应权限,尤其是使用SSE-KMS时。可通过SDK、图形化工具或编程框架集成下载,发起请求时,OSS自动处理解密,客户端接收解密后的数据。权限、下载方式选择及请求发起是关键步骤。
9 1

相关产品

  • 对象存储