全部產品
Search
文件中心

Object Storage Service:服務端簽名直傳並設定上傳回調

更新時間:Nov 30, 2024

本文主要介紹如何基於Post Policy的使用規則在服務端通過各種語言程式碼完成簽名,並且設定上傳回調,然後通過表單直傳資料到OSS。

背景資訊

大多數情況下,使用者上傳檔案後,應用伺服器需要知道使用者上傳了哪些檔案以及檔案名稱;如果上傳了圖片,還需要知道圖片的大小等,為此OSS提供了上傳回調方案。

流程介紹

當使用者要上傳一個檔案到OSS,而且希望將上傳的結果返回給應用伺服器時,需要設定一個回呼函數,將請求告知應用伺服器。使用者上傳完檔案後,不會直接得到返回結果,而是先通知應用伺服器,再把結果轉達給使用者。

操作樣本

服務端簽名直傳並設定上傳回調提供了以下語言的操作樣本:

流程解析

以下根據流程講解核心代碼和訊息內容。

  1. 使用者嚮應用伺服器請求上傳Policy和回調。

    在用戶端源碼中的upload.js檔案中,如下程式碼片段的變數serverUrl的值可以用來設定應用伺服器的URL。設定好之後,用戶端會向該serverUrl發送Get請求來擷取需要的資訊。

    // serverUrl是使用者擷取簽名和Policy等資訊的應用伺服器的URL,請將下面的IP和Port配置為您自己的真實資訊。
    serverUrl = 'http:/88.88.XX.XXX:8888';
  2. 應用伺服器返回上傳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

  3. 使用者直接向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,
     };
  4. 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"
  5. 應用伺服器返迴響應給OSS。

    應用伺服器根據OSS發送訊息中的authorization來進行驗證,如果驗證通過,則向OSS返回如下JSON格式的成功訊息。

    {
    "String value": "ok",
    "Key": "Status"
    }
  6. 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無法自訂。