利用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
" % (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 = "
".join(str(item_) for item_ in items) + "
"
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()
`xx1e^$]ixb5fx97x9bx86xe2x8d#xf2xc7`
常見錯誤是直接對計算出的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進行預覽等處理。
相關文章
- 實現簡單的csv檔案上傳和bootstrap表格的下載boot
- 簡單介紹ASP.NET Core實現檔案上傳和下載ASP.NET
- Node分片上傳和OSS上傳
- 前端實現檔案下載和拖拽上傳前端
- vue+element+oss實現前端分片上傳和斷點續傳Vue前端斷點
- OSS網頁上傳和斷點續傳(OSS配置篇)網頁斷點
- rshiny1:簡單的接入api實現下載功能API
- 在Oracle中存取BLOB物件實現檔案的上傳和下載Oracle物件
- APICloud 實現文件下載和預覽功能APICloud
- 檔案上傳和下載功能
- 物件儲存OSS上傳、下載發生”便祕”物件
- 基於Js和Java實現xlsxxls文件的匯入和下載JSJava
- OSS網頁上傳和斷點續傳(STSToken篇)網頁斷點
- java實現sftp檔案的上傳下載JavaFTP
- 利用swagger和API Version實現api版本控制SwaggerAPI
- SpringMVC中的檔案上傳和下載SpringMVC
- 基於servlet的檔案上傳和下載Servlet
- OSS網頁上傳和斷點續傳(終結篇)網頁斷點
- 輕輕鬆鬆實現本地和雲主機之間的檔案上傳下載
- Java實現Fast DFS、伺服器、OSS上傳JavaAST伺服器
- python寫的FTP簡單上傳下載檔案薦PythonFTP
- Feign實現檔案上傳下載
- 使用osscsdk自定義上傳和下載callback
- 用SecureCRT來上傳和下載資料Securecrt
- python 遍歷oss 實現批次下載Python
- vue實現Excel檔案的上傳與下載VueExcel
- 檔案上傳原理和實現
- springboot 中檔案的上傳和下載Spring Boot
- Redux 原理和簡單實現Redux
- throttle和debounce簡單實現
- 利用tess-two和cv4j實現簡單的ocr功能
- Spring Boot MVC 單張圖片和多張圖片上傳 和通用檔案下載Spring BootMVC
- 使阿里oss實現前端程式碼自動上傳阿里前端
- SpringMVC實現檔案上傳&下載(2)SpringMVC
- 上傳檔案到七牛雲端儲存的java api一個簡單的demo實現JavaAPI
- 利用 XForms 和 ODF 實現互動式辦公文件ORM
- 面試題:上傳和下載怎麼測試?面試題
- Java Struts檔案上傳和下載詳解Java