337
小米6
Callback__關於Object操作_API 參考_對象存儲 OSS-阿裏雲
上傳回調
用戶隻需要在發送給OSS的請求中攜帶相應的Callback參數,即能實現回調。現在支持CallBack的API 接口有:PutObject、PostObject、CompleteMultipartUpload。
構造CallBack參數
CallBack參數是由一段經過base64編碼的Json字串,用戶關鍵需要指定請求回調的服務器URL(callbackUrl)以及回調的內容(callbackBody)。詳細的Json字段如下:
字段 | 含義 | |
---|---|---|
callbackUrl | - 文件上傳成功後OSS向此url發送回調請求,請求方法為POST,body為callbackBody指定的內容。正常情況下,該url需要響應“HTTP/1.1 200 OK”,body必須為JSON格式,響應頭Content-Length必須為合法的值,且不超過3MB。 - 支持同時配置最多5個url,以”;”分割。OSS會依次發送請求直到第一個返回成功為止。 - 如果沒有配置或者值為空則認為沒有配置callback。 - 支持HTTPS地址。 - 為了保證正確處理中文等情況,callbackUrl需做url編碼處理,比如 https://example.com/中文.php?key=value&中文名稱=中文值 需要編碼成 https://example.com/%E4%B8%AD%E6%96%87.php?key=value&%E4%B8%AD%E6%96%87%E5%90%8D%E7%A7%B0=%E4%B8%AD%E6%96%87%E5%80%BC |
必選項 |
callbackHost | - 發起回調請求時Host頭的值,隻有在設置了callbackUrl時才有效。 - 如果沒有配置 callbckHost,則會解析callbackUrl中的url並將解析出的host填充到callbackHost中 |
可選項 |
callbackBody | - 發起回調時請求body的值,例如:key=$(key)&etag=$(etag)&my_var=$(x:my_var)。 - 支持OSS係統變量、自定義變量和常量,支持的係統變量如下表所示 。自定義變量的支持方式在PutObject和CompleteMultipart中是通過callback-var來傳遞,在PostObject中則是將各個變量通過表單域來傳遞。 |
必選項 |
callbackBodyType | - 發起回調請求的Content-Type,支持application/x-www-form-urlencoded和application/json,默認為前者。 - 如果為application/x-www-form-urlencoded,則callbackBody中的變量將會被經過url編碼的值替換掉,如果為application/json,則會按照json格式替換其中的變量。 |
可選項 |
示例json串如下
{
"callbackUrl":"121.101.166.30/test.php",
"callbackHost":"oss-cn-hangzhou.aliyuncs.com",
"callbackBody":"{"mimeType":${mimeType},"size":${size}}",
"callbackBodyType":"application/json"
}
{
"callbackUrl":"121.43.113.8:23456/index.html",
"callbackBody":"bucket=${bucket}&object=${object}&etag=${etag}&size=${size}&mimeType=${mimeType}&imageInfo.height=${imageInfo.height}&imageInfo.width=${imageInfo.width}&imageInfo.format=${imageInfo.format}&my_var=${x:my_var}"
}
其中callbackBody中可以設置的係統變量有,其中imageInfo針對於圖片格式,如果為非圖片格式都為空:
係統變量 | 含義 |
---|---|
bucket | bucket |
object | object |
etag | 文件的etag,即返回給用戶的etag字段 |
size | object大小,CompleteMultipartUpload時為整個object的大小 |
mimeType | 資源類型,如jpeg圖片的資源類型為image/jpeg |
imageInfo.height | 圖片高度 |
imageInfo.width | 圖片寬度 |
imageInfo.format | 圖片格式,如jpg、png等 |
自定義參數
用戶可以通過callback-var參數來配置自定義參數。
自定義參數是一個Key-Value的Map,用戶可以配置自己需要的參數到這個Map。在OSS發起POST回調請求的時候,會將這些參數和上一節所述的係統參數一起放在POST請求的body中以方便接收回調方獲取。
構造自定義參數的方法和callback參數的方法是一樣的,也是以json格式來傳遞。該json字符串就是一個包含所有自定義參數的Key-Value的Map。這裏有個特別需要注意的地方就是,用戶自定義參數的Key一定要以x:開頭,且必須為小寫。否則OSS會返回錯誤。假定用戶需要設定兩個自定義的參數分別為x:var1和x:var2,對應的值分別為value1和value2,那麼構造出來的json格式如下:
{
"x:var1":"value1",
"x:var2":"值2"
}
構造回調請求
構造完成上述的callback和callback-var兩個參數之後,一共有三種方式傳給OSS。其中callback為必填參數,callback-var為可選參數,如果沒有自定義參數的話可以不用添加callback-var字段。這三種方式如下:
- 在URL中攜帶參數。
- 在Header中攜帶參數。
- 在POST請求的body中使用表單域來攜帶參數,在使用POST請求上傳Object的時候隻能使用這種方式來指定回調參數。
這三種方式隻能同時使用其中一種,否則OSS會返回InvalidArgument錯誤。
要將參數附加到OSS的請求中,首先要將上文構造的json字符串使用base64編碼,然後按照如下的方法附加到OSS的請求中:
- 如果在URL中攜帶參數。把
callback=[CallBack]
或者callback-var=[CallBackVar]
作為一個url參數帶入請求發送。計算簽名CanonicalizedResource時 ,將callback或者callback-var當做一個sub-resource計算在內 - 如果在Header中攜帶參數。把
x-oss-callback=[CallBack]
或者x-oss-callback-var=[CallBackVar]
作為一個head帶入請求發送。在計算簽名CanonicalizedOSSHeaders時,將x-oss-callback-var和x-oss-callback計算在內。如下示例:
PUT /test.txt HTTP/1.1
Host: callback-test.oss-test.aliyun-inc.com
Accept-ncoding: identity
Content-Length: 5
x-oss-callback-var: eyJ4Om15X3ZhciI6ImZvci1jYWxsYmFjay10ZXN0In0=
User-Agent: aliyun-sdk-python/0.4.0 (Linux/2.6.32-220.23.2.ali1089.el5.x86_64/x86_64;2.5.4)
x-oss-callback: eyJjYWxsYmFja1VybCI6IjEyMS40My4xMTMuODoyMzQ1Ni9pbmRleC5odG1sIiwgICJjYWxsYmFja0JvZHkiOiJidWNrZXQ9JHtidWNrZXR9Jm9iamVjdD0ke29iamVjdH0mZXRhZz0ke2V0YWd9JnNpemU9JHtzaXplfSZtaW1lVHlwZT0ke21pbWVUeXBlfSZpbWFnZUluZm8uaGVpZ2h0PSR7aW1hZ2VJbmZvLmhlaWdodH0maW1hZ2VJbmZvLndpZHRoPSR7aW1hZ2VJbmZvLndpZHRofSZpbWFnZUluZm8uZm9ybWF0PSR7aW1hZ2VJbmZvLmZvcm1hdH0mbXlfdmFyPSR7eDpteV92YXJ9In0=
Host: callback-test.oss-test.aliyun-inc.com
Expect: 100-Continue
Date: Mon, 14 Sep 2015 12:37:27 GMT
Content-Type: text/plain
Authorization: OSS mlepou3zr4u7b14:5a74vhd4UXpmyuudV14Kaen5cY4=
Test
- 如果需要在POST上傳Object的時候附帶回調參數會稍微複雜一點,callback參數要使用獨立的表單域來附加,如下麵的示例:
--9431149156168
Content-Disposition: form-data; name="callback"
eyJjYWxsYmFja1VybCI6IjEwLjEwMS4xNjYuMzA6ODA4My9jYWxsYmFjay5waHAiLCJjYWxsYmFja0hvc3QiOiIxMC4xMDEuMTY2LjMwIiwiY2FsbGJhY2tCb2R5IjoiZmlsZW5hbWU9JChmaWxlbmFtZSkmdGFibGU9JHt4OnRhYmxlfSIsImNhbGxiYWNrQm9keVR5cGUiOiJhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWQifQ==
如果擁有自定義參數的話,不能直接將callback-var參數直接附加到表單域中,每個自定義的參數都需要使用獨立的表單域來附加,舉個例子,如果用戶的自定義參數的json為
{
"x:var1":"value1",
"x:var2":"value2"
}
那麼POST請求的表單域應該如下:
--9431149156168
Content-Disposition: form-data; name="callback"
eyJjYWxsYmFja1VybCI6IjEwLjEwMS4xNjYuMzA6ODA4My9jYWxsYmFjay5waHAiLCJjYWxsYmFja0hvc3QiOiIxMC4xMDEuMTY2LjMwIiwiY2FsbGJhY2tCb2R5IjoiZmlsZW5hbWU9JChmaWxlbmFtZSkmdGFibGU9JHt4OnRhYmxlfSIsImNhbGxiYWNrQm9keVR5cGUiOiJhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWQifQ==
--9431149156168
Content-Disposition: form-data; name="x:var1"
value1
--9431149156168
Content-Disposition: form-data; name="x:var2"
value2
同時可以在policy中添加callback條件(如果不添加callback,則不對該參數做上傳驗證)如:
{ "expiration": "2014-12-01T12:00:00.000Z",
"conditions": [
{"bucket": "johnsmith" },
{"callback": "eyJjYWxsYmFja1VybCI6IjEwLjEwMS4xNjYuMzA6ODA4My9jYWxsYmFjay5waHAiLCJjYWxsYmFja0hvc3QiOiIxMC4xMDEuMTY2LjMwIiwiY2FsbGJhY2tCb2R5IjoiZmlsZW5hbWU9JChmaWxlbmFtZSkiLCJjYWxsYmFja0JvZHlUeXBlIjoiYXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVkIn0="},
["starts-with", "$key", "user/eric/"],
]
}
發起回調請求
如果文件上傳成功,OSS會根據用戶的請求中的callback參數和自定義參數(callback-var參數),將特定內容以POST方式發送給應用服務器。
POST /index.html HTTP/1.0
Host: 121.43.113.8
Connection: close
Content-Length: 181
Content-Type: application/x-www-form-urlencoded
User-Agent: ehttp-client/0.0.1
bucket=callback-test&object=test.txt&etag=D8E8FCA2DC0F896FD7CB4CB0031BA249&size=5&mimeType=text%2Fplain&imageInfo.height=&imageInfo.width=&imageInfo.format=&x:var1=for-callback-test
返回回調結果
比如應用服務器端返回的回應請求為:
HTTP/1.0 200 OK
Server: BaseHTTP/0.3 Python/2.7.6
Date: Mon, 14 Sep 2015 12:37:27 GMT
Content-Type: application/json
Content-Length: 9
{"a":"b"}
返回上傳結果
再給客戶端的內容為:
HTTP/1.1 200 OK
Date: Mon, 14 Sep 2015 12:37:27 GMT
Content-Type: application/json
Content-Length: 9
Connection: keep-alive
ETag: "D8E8FCA2DC0F896FD7CB4CB0031BA249"
Server: AliyunOSS
x-oss-bucket-version: 1442231779
x-oss-request-id: 55F6BF87207FB30F2640C548
{"a":"b"}
需要注意的是,如果類似CompleteMultipartUpload這樣的請求,在返回請求本身body中存在內容(如XMl格式的信息),使用上傳回調功能後會覆蓋原有的body的內容如{"a":"b"}
,希望對此處做好判斷處理。
回調簽名
用戶設置callback參數後,OSS將按照用戶設置的callbackUrl發送POST回調請求給用戶的應用服務器。應用服務器收到回調請求之後,如果希望驗證回調請求確實是由OSS發起的話,那麼可以通過在回調中帶上簽名來驗證OSS的身份。
生成簽名
簽名在OSS端發生,采用RSA非對稱方式簽名,私鑰加密的過程為:
authorization = base64_encode(rsa_sign(private_key, url_decode(path) + query_string + ‘n’ + body, md5))
說明:其中private_key為私鑰,隻有oss知曉,path為回調請求的資源路徑,query_string為查詢字符串,body為回調的消息體,所以簽名過程由以下幾步組成:
- 獲取待簽名字符串:資源路徑經過url解碼後,加上原始的查詢字符串,加上一個回車符,加上回調消息體
- RSA簽名:使用秘鑰對待簽名字符串進行簽名,簽名的hash函數為md5
- 將簽名後的結果做base64編碼,得到最終的簽名,簽名放在回調請求的authorization頭中
如下例:
POST /index.php?id=1&index=2 HTTP/1.0
Host: 121.43.113.8
Connection: close
Content-Length: 18
authorization: kKQeGTRccDKyHB3H9vF+xYMSrmhMZjzzl2/kdD1ktNVgbWEfYTQG0G2SU/RaHBovRCE8OkQDjC3uG33esH2txA==
Content-Type: application/x-www-form-urlencoded
User-Agent: ehttp-client/0.0.1
x-oss-pub-key-url: aHR0cDovL2dvc3NwdWJsaWMuYWxpY2RuLmNvbS9jYWxsYmFja19wdWJfa2V5X3YxLnBlbQ==
bucket=yonghu-test
path為/index.php
,query_string為?id=1&index=2
,body為bucket=yonghu-test
,最終簽名結果為kKQeGTRccDKyHB3H9vF+xYMSrmhMZjzzl2/kdD1ktNVgbWEfYTQG0G2SU/RaHBovRCE8OkQDjC3uG33esH2txA==
驗證簽名
驗證簽名的過程即為簽名的逆過程,由應用服務器驗證,過程如下:
Result = rsa_verify(public_key, md5(url_decode(path) + query_string + ‘n’ + body), base64_decode(authorization))
字段的含義與簽名過程中描述相同,其中public_key為公鑰, authorization為回調頭中的簽名,整個驗證簽名的過程分為以下幾步:
- 回調請求的x-oss-pub-key-url頭保存的是公鑰的url地址的base64編碼,因此需要對其做base64解碼後獲取到公鑰,即
public_key = urlopen(base64_decode(x-oss-pub-key-url頭的值))
這裏需要注意,用戶需要校驗x-oss-pub-key-url
頭的值必須以https://gosspublic.alicdn.com/
或者https://gosspublic.alicdn.com/
開頭,目的是為了保證這個publickey是由OSS頒發的。
- 獲取base64解碼後的簽名
signature = base64_decode(authorization頭的值)
- 獲取待簽名字符串,方法與簽名一致
sign_str = url_decode(path) + query_string + ‘n’ + body
- 驗證簽名
result = rsa_verify(public_key, md5(sign_str), signature)
以上例為例:
- 獲取到公鑰的url地址,即
aHR0cDovL2dvc3NwdWJsaWMuYWxpY2RuLmNvbS9jYWxsYmFja19wdWJfa2V5X3YxLnBlbQ==
經過base64解碼後得到https://gosspublic.alicdn.com/callback_pub_key_v1.pem
- 簽名頭
kKQeGTRccDKyHB3H9vF+xYMSrmhMZjzzl2/kdD1ktNVgbWEfYTQG0G2SU/RaHBovRCE8OkQDjC3uG33esH2txA==
做base64解碼(由於為非打印字符,無法顯示出解碼後的結果) - 獲取待簽名字符串,即url_decode(“index.php”) + “?id=1&index=2” + “n” + “bucket=yonghu-test”,並做md5
- 驗證簽名
應用服務器示例
以下為一段python示例,演示了一個簡單的應用服務器,主要是說明驗證簽名的方法,此示例需要安裝M2Crypto庫
import httplib
import base64
import md5
import urllib2
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
from M2Crypto import RSA
from M2Crypto import BIO
def get_local_ip():
try:
csock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
csock.connect(('8.8.8.8', 80))
(addr, port) = csock.getsockname()
csock.close()
return addr
except socket.error:
return ""
class MyHTTPRequestHandler(BaseHTTPRequestHandler):
'''
def log_message(self, format, *args):
return
'''
def do_POST(self):
#get public key
pub_key_url = ''
try:
pub_key_url_base64 = self.headers['x-oss-pub-key-url']
pub_key_url = pub_key_url_base64.decode('base64')
if not pub_key_url.startswith("https://gosspublic.alicdn.com/") and not pub_key_url.startswith("https://gosspublic.alicdn.com/"):
self.send_response(400)
self.end_headers()
return
url_reader = urllib2.urlopen(pub_key_url)
#you can cache it
pub_key = url_reader.read()
except:
print 'pub_key_url : ' + pub_key_url
print 'Get pub key failed!'
self.send_response(400)
self.end_headers()
return
#get authorization
authorization_base64 = self.headers['authorization']
authorization = authorization_base64.decode('base64')
#get callback body
content_length = self.headers['content-length']
callback_body = self.rfile.read(int(content_length))
#compose authorization string
auth_str = ''
pos = self.path.find('?')
if -1 == pos:
auth_str = urllib2.unquote(self.path) + 'n' + callback_body
else:
auth_str = urllib2.unquote(self.path[0:pos]) + self.path[pos:] + 'n' + callback_body
print auth_str
#verify authorization
auth_md5 = md5.new(auth_str).digest()
bio = BIO.MemoryBuffer(pub_key)
rsa_pub = RSA.load_pub_key_bio(bio)
try:
result = rsa_pub.verify(auth_md5, authorization, 'md5')
except:
result = False
if not result:
print 'Authorization verify failed!'
print 'Public key : %s' % (pub_key)
print 'Auth string : %s' % (auth_str)
self.send_response(400)
self.end_headers()
return
#do something accoding to callback_body
#response to OSS
resp_body = '{"Status":"OK"}'
self.send_response(200)
self.send_header('Content-Type', 'application/json')
self.send_header('Content-Length', str(len(resp_body)))
self.end_headers()
self.wfile.write(resp_body)
class MyHTTPServer(HTTPServer):
def __init__(self, host, port):
HTTPServer.__init__(self, (host, port), MyHTTPRequestHandler)
if '__main__' == __name__:
server_ip = get_local_ip()
server_port = 23451
server = MyHTTPServer(server_ip, server_port)
server.serve_forever()
其它語言實現的應用服務器如下:
Java版本
- 下載地址:點擊這裏
- 運行方法:解壓包運行
java -jar oss-callback-server-demo.jar 9000
(9000就運行的端口,可以自己指定)
PHP版本:
- 下載地址:點擊這裏
- 運行方法:部署到Apache環境下,因為PHP本身語言的特點,取一些數據頭部會依賴於環境。所以可以參考例子根據所在環境修改。
Python版本:
- 下載地址:點擊這裏
- 運行方法:解壓包直接運行
python callback_app_server.py
,運行該程序需要安裝rsa的依賴。
Ruby版本:
- 下載地址:點擊這裏
- 運行方法: ruby aliyun_oss_callback_server.rb
特別須知
如果傳入的callback或者callback-var不合法,則會返回400錯誤,錯誤碼為”InvalidArgument”,不合法的情況包括以下幾類:
- PutObject()和CompleteMultipartUpload()接口中url和header同時傳入callback(x-oss-callback)或者callback-var(x-oss-callback-var)參數
- callback或者callback-var(PostObject()由於沒有callback-var參數,因此沒有此限製,下同)參數過長(超過5KB)
- callback或者callback-var沒有經過base64編碼
- callback或者callback-var經過base64解碼後不是合法的json格式
- callback參數解析後callbackUrl字段包含的url超過限製(5個),或者url中傳入的port不合法,比如
{"callbackUrl":"10.101.166.30:test", "callbackBody":"test"}
- callback參數解析後callbackBody字段為空
- callback參數解析後callbackBodyType字段的值不是”application/x-www-form-urlencoded”或者”application/json”
- callback參數解析後callbackBody字段中變量的格式不合法,合法的格式為
${var}
- callback-var參數解析後不是預期的json格式,預期的格式應該為
{"x:var1":"value1","x:var2":"value2"...}
如果回調失敗,則返回203,錯誤碼為”CallbackFailed”,回調失敗隻是表示OSS沒有收到預期的回調響應,不代表應用服務器沒有收到回調請求(比如應用服務器返回的內容不是json格式),另外,此時文件已經成功上傳到了OSS
應用服務器返回OSS的響應必須帶有Content-Length的Header,Body大小不要超過1MB。
最後更新:2016-12-14 10:26:26
上一篇:
PostObject__關於Object操作_API 參考_對象存儲 OSS-阿裏雲
下一篇:
PutSymlink__關於Object操作_API 參考_對象存儲 OSS-阿裏雲
新購買ECS或重置ECS後安全部署方法__技術分享_技術運維問題_漏洞掃描-阿裏雲
CDN服務如何開啟GZIP壓縮功能___產品使用問題_CDN-阿裏雲
VirtualMFADevice__數據類型_RAM API文檔_訪問控製-阿裏雲
雲服務器 ECS > 用戶指南 > 磁盤 > 掛載數據盤
阿裏雲的 IaaS 收入相當於中國另 7 個玩家的總和,占有 40.7% 的市場份額
負載均衡是否支持CNAME__常見問題_負載均衡-阿裏雲
清理RDS實例日誌__實例管理_API 參考_雲數據庫 RDS 版-阿裏雲
訂閱關係一致__最佳實踐_消息隊列 MQ-阿裏雲
主機監控概覽__主機監控_用戶指南_雲監控-阿裏雲
步驟 3-3:創建和查詢多維數據集__創建監控任務_用戶指南_業務實時監控服務 ARMS-阿裏雲
相關內容
常見錯誤說明__附錄_大數據計算服務-阿裏雲
發送短信接口__API使用手冊_短信服務-阿裏雲
接口文檔__Android_安全組件教程_移動安全-阿裏雲
運營商錯誤碼(聯通)__常見問題_短信服務-阿裏雲
設置短信模板__使用手冊_短信服務-阿裏雲
OSS 權限問題及排查__常見錯誤及排除_最佳實踐_對象存儲 OSS-阿裏雲
消息通知__操作指南_批量計算-阿裏雲
設備端快速接入(MQTT)__快速開始_阿裏雲物聯網套件-阿裏雲
查詢API調用流量數據__API管理相關接口_API_API 網關-阿裏雲
使用STS訪問__JavaScript-SDK_SDK 參考_對象存儲 OSS-阿裏雲