本文主要介紹如何基於Post Policy的使用規則在服務端通過各種語言程式碼完成簽名,並且設定上傳回調,然後通過表單直傳資料到OSS。
背景資訊
大多數情況下,使用者上傳檔案後,應用伺服器需要知道使用者上傳了哪些檔案以及檔案名稱;如果上傳了圖片,還需要知道圖片的大小等,為此OSS提供了上傳回調方案。
流程介紹
當使用者要上傳一個檔案到OSS,而且希望將上傳的結果返回給應用伺服器時,需要設定一個回呼函數,將請求告知應用伺服器。使用者上傳完檔案後,不會直接得到返回結果,而是先通知應用伺服器,再把結果轉達給使用者。
操作樣本
流程解析
以下根據流程講解核心代碼和訊息內容。
使用者嚮應用伺服器請求上傳Policy和回調。
在用戶端源碼中的
upload.js
檔案中,如下程式碼片段的變數serverUrl
的值可以用來設定應用伺服器的URL。設定好之後,用戶端會向該serverUrl
發送Get請求來擷取需要的資訊。// serverUrl是使用者擷取簽名和Policy等資訊的應用伺服器的URL,請將下面的IP和Port配置為您自己的真實資訊。 serverUrl = 'http:/88.88.XX.XXX:8888';
應用伺服器返回上傳Policy和回調設定代碼。
應用伺服器側的簽名直傳服務會處理用戶端發過來的Get請求訊息,您可以設定對應的代碼讓應用伺服器能夠給用戶端返回正確的訊息。各個語言版本的配置文檔中都有明確的說明供您參考。
以下是簽名直傳服務返回給用戶端訊息Body內容的樣本,Body的內容將作為用戶端上傳檔案的重要參數。
{ "accessid":"LTAI**********", "host":"http://post-test.oss-cn-hangzhou.aliyuncs.com", "policy":"eyJleHBpcmF0aW9uIjoiMjAxNS0xMS0wNVQyMDoyMzoyM1oiLCJjxb25kaXRpb25zIjpbWyJjcb250ZW50LWxlbmd0aC1yYW5nZSIsMCwxMDQ4NTc2MDAwXSxbInN0YXJ0cy13aXRoIiwiJGtleSIsInVzZXItZGlyXC8i****", "signature":"I2u5**********", "expire":1446727949, "callback":"eyJjYWxsYmFja1VybCI6Imh0dHA6Ly9vc3MtZGVtby5hbGl5dW5jcy5jb206MjM0NTAiLAoiY2FsbGJhY2tCb2R5IjoiZmlsZW5hbWU9JHtvYmplY3R9JnNpemU9JHtzaXplfSZtaW1lVHlwZT0ke21pbWVUeXBlfSZoZWlnaHQ9JHtpbWFnZUluZm8uaGVpZ2h0fSZ3aWR0aD0ke2ltYWdlSW5mby53aWR0aH0iLAoiY2FsbGJhY2tCb2R5VHlwZSI6ImFwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZCJ9", "dir":"user-dirs/" }
上述樣本的callback內容採用的是Base64編碼。經過Base64解碼後的內容如下:
{"callbackUrl":"http://oss-demo.aliyuncs.com:23450", "callbackBody":"filename=${object}&size=${size}&mimeType=${mimeType}&height=${imageInfo.height}&width=${imageInfo.width}", "callbackBodyType":"application/x-www-form-urlencoded"}
說明以上僅為回調樣本,您可以通過修改服務端代碼自行設定回調。
參數
說明
callbackUrl
OSS向伺服器發送的URL請求。
callbackHost
OSS發送該請求時,要求標頭部所帶的Host頭。
callbackBody
OSS發送給應用伺服器的內容。如果是檔案,可以是檔案的名稱、大小、類型等。如果是圖片,可以是圖片的高度、寬度等。
callbackBodyType
請求發送的Content-Type。
取值:
application/x-www-form-urlencoded(預設值)
application/json
使用者直接向OSS傳送檔案上傳請求。
在用戶端源碼
upload.js
檔案中,callbackbody
的值是步驟2中應用伺服器返回給用戶端訊息Body中Callback的內容。new_multipart_params = { 'key' : key + '${filename}', 'policy': policyBase64, 'OSSAccessKeyId': accessid, // 設定服務端返回狀態代碼為200,不設定則預設返回狀態代碼204。 'success_action_status' : '200', 'callback': callbackbody, 'signature': signature, };
OSS根據使用者的回調設定,發送回調請求給應用伺服器。
用戶端上傳檔案到OSS結束後,OSS解析用戶端的上傳回調設定,發送Post回調請求給應用伺服器。訊息內容樣本如下:
說明此樣本使用的是V1版本簽名,如需使用V4簽名發送請求,可參考V1簽名升級為V4簽名指引。
Hypertext Transfer Protocol POST / HTTP/1.1\r\n Host47.97.XXX.XX53\r\n Connection: close\r\n Content-Length: 76\r\n Authorization: fsNx********//a8x6v2lI1********\r\n Content-MD5: eiEMyp7lbL8KStPBzMdr9w==\r\n Content-Type: application/x-www-form-urlencoded\r\n Date: Sat, 15 Sep 2018 10:24:12 GMT\r\n User-Agent: aliyun-oss-callback\r\n x-oss-additional-headers: \r\n x-oss-bucket: signedcallback\r\n x-oss-owner: 137918634953****\r\n x-oss-pub-key-url: aHR0cDovL2dvc3NwdWJsaWMuYWxpY2RuLmNvbS9jYWxsYmFja19wdWJfa2V5X3YxLnaH****\r\n x-oss-request-id: 534B371674E88A4D8906****\r\n x-oss-requester: 137918634953****\r\n x-oss-signature-version: 1.0\r\n x-oss-tag: CALLBACK\r\n eagleeye-rpcid: 0.1\r\n \r\n [Full request URI: http://47.xx.xx.53/] [HTTP request 1/1] [Response in frame: 39] File Data: 76 bytes HTML Form URL Encoded: application/x-www-form-urlencoded Form item: "filename" = ".snappython.png" Form item: "size" = "6014" Form item: "mimeType" = "image/png" Form item: "height" = "221"
應用伺服器返迴響應給OSS。
應用伺服器根據OSS發送訊息中的
authorization
來進行驗證,如果驗證通過,則向OSS返回如下JSON格式的成功訊息。{ "String value": "ok", "Key": "Status" }
OSS將應用伺服器返回的訊息返回給使用者。
用戶端源碼解析
用戶端源碼下載地址:aliyun-oss-appserver-js-master.zip
用戶端JavaScript代碼使用的是Plupload組件。Plupload是一款簡單易用且功能強大的檔案上傳工具, 支援多種上傳方式,包括HTML5、Flash、SilverLight、HTML4。它會智能檢測當前環境,選擇最適合的上傳方式,並且會優先採用HTML5方式。詳情請參見Plupload官網。
以下為常見功能的程式碼範例:
設定成隨機檔案名稱
若上傳時採用固定格式的隨機檔案名稱,且尾碼跟用戶端檔案名稱保持一致,可以將函數改為:
function check_object_radio() { g_object_name_type = 'random_name'; }
設定成使用者的檔案名稱
如果想在上傳時設定成使用者的檔案名稱,可以將函數改為:
function check_object_radio() { g_object_name_type = 'local_name'; }
設定上傳目錄
上傳的目錄由服務端指定, 每個用戶端只能上傳到指定的目錄,實現安全隔離。下面的代碼以PHP為例,將上傳目錄改成abc/,注意目錄必須以正斜線(/)結尾。
$dir ='abc/';
設定上傳過濾條件
您可以利用Plupload的屬性filters設定上傳的過濾條件,如設定只能上傳圖片、上傳檔案的大小、不能有重複上傳等。
var uploader = new plupload.Uploader({ …… filters: { mime_types : [ // 只允許上傳圖片和ZIP檔案。 { title : "Image files", extensions : "jpg,gif,png,bmp" }, { title : "Zip files", extensions : "zip" } ], // 最大隻能上傳400KB的檔案。 max_file_size : '400kb', // 不允許選取重複檔案。 prevent_duplicates : true },
mime_types:限制上傳的檔案尾碼。
max_file_size:限制上傳的檔案大小。
prevent_duplicates:限制不能重複上傳。
擷取上傳後的檔案名稱
如果要知道檔案上傳成功後的檔案名稱,可以用Plupload調用FileUploaded事件擷取,如下所示:
FileUploaded: function(up, file, info) { if (info.status == 200) { document.getElementById(file.id).getElementsByTagName('b')[0].innerHTML = 'upload to oss success, object name:' + get_uploaded_object_name(file.name); } else { document.getElementById(file.id).getElementsByTagName('b')[0].innerHTML = info.response; } }
可以利用
get_uploaded_object_name(file.name)
函數,得到上傳到OSS的檔案名稱,其中file.name
記錄了本地檔案上傳的名稱。上傳簽名
JavaScript可以從服務端擷取policyBase64、accessid、signature這三個變數,核心代碼如下:
function get_signature() { // 判斷expire的值是否超過了目前時間,如果超過了目前時間,則重新擷取簽名,緩衝時間為3秒。 now = timestamp = Date.parse(new Date()) / 1000; if (expire < now + 3) { body = send_request() var obj = eval ("(" + body + ")"); host = obj['host'] policyBase64 = obj['policy'] accessid = obj['accessid'] signature = obj['signature'] expire = parseInt(obj['expire']) callbackbody = obj['callback'] key = obj['dir'] return true; } return false; };
從服務端返回的訊息解析如下:
說明以下僅為樣本,並不要求相同的格式,但必須包含accessid、policy、signature三個值。
{"accessid":"LTAI**********", "host":"http://post-test.oss-cn-hangzhou.aliyuncs.com", "policy":"eyJleHBpcmF0aW9uIjoiMjAxNS0xMS0wNVQyMDoyMzoyM1oiLCJjxb25kaXRpb25zIjpbWyJjcb250ZW50LWxlbmd0aC1yYW5nZSIsMCwxMDQ4NTc2MDAwXSxbInN0YXJ0cy13aXRoIiwiJGtleSIsInVzZXItZGlyXC8i****", "signature":"I2u5**********", "expire":1446726203,"dir":"user-dir/"}
accessid:使用者請求的accessid。
host:使用者要往哪個網域名稱發送上傳請求。
policy:使用者表單上傳的策略(Policy),是經過Base64編碼過的字串。詳情請參見Post Policy。
signature:對Policy簽名後的字串。
expire:上傳策略Policy失效時間,在服務端指定。失效時間之前都可以利用此Policy上傳檔案,無需每次上傳都去服務端擷取簽名。
說明為了減少服務端的壓力,初始化上傳時,每上傳一個檔案,擷取一次簽名。再次上傳檔案時,對目前時間與簽章時間進行比較,並查看簽章時間是否失效。如果簽名已失效,則重新擷取一次簽名;如果簽名未失效,則使用之前的簽名。
解析Policy的內容如下:
{"expiration":"2015-11-05T20:23:23Z", "conditions":[["content-length-range",0,1048576000],// 上傳檔案的大小限制預設為5 GB。您可以自訂上傳檔案的大小限制。如果超過此限制,檔案上傳到OSS會報錯。 ["starts-with","$key","user-dir/"]]}
上面Policy中增加了starts-with,用來指定此次上傳的檔案名稱必須以user-dir開頭,使用者也可以自行指定。增加starts-with的原因是,在眾多情境下,一個應用對應一個Bucket。為了防止資料覆蓋,使用者上傳到OSS的每個檔案都可以有特定的首碼。但這樣存在一個問題,使用者擷取到這個Policy後,在失效期內都能修改上傳首碼,從而上傳到其他使用者的目錄下。為解決該問題,可在應用伺服器端指定使用者上傳檔案的首碼。這樣即便使用者擷取了Policy也沒有辦法上傳到其他使用者的目錄,從而保證了資料的安全性。
設定應用伺服器的地址
在用戶端源碼
upload.js
檔案中,如下程式碼片段的變數serverUrl
的值可以用來設定應用伺服器的URL,設定完成後,用戶端會向該serverUrl
發送Get請求來擷取資訊。// serverUrl是使用者擷取簽名和Policy等資訊的應用伺服器的URL,請將下面的IP和Port配置為您自己的真實資訊。 serverUrl = 'http:/88.88.XX.XX8:8888'
常見問題
前端如何?批量上傳檔案?
OSS沒有開放批量上傳介面,如果需要批量上傳,您可以使用一個迴圈去上傳所有檔案,樣本與上傳單個檔案一致。
使用服務端簽名直傳並設定上傳回調時支援自訂回調請求的header頭部資訊嗎?
不支援。您只能自訂回調參數,也就是回調的body,但是OSS回調請求您的callback url時攜帶的header無法自訂。