阿里云 OSS 網頁端直傳實踐簡介

來源:Web 端直傳實踐簡介

目的

通過三個例子介紹如何在 HTML 表單提交直傳 OSS:

  1. 簽名在客戶端(javascript)完成,然后直接通過表單上傳到 OSS。
  2. 簽名在服務端(php)完成,然后直接通過表單上傳到 OSS。
  3. 簽名在服務端(php)完成,并且服務端設置了上傳后回調。然后直接通過表單上傳到 OSS,OSS回調完應用服務器再返回給用戶。

基礎篇:JavaScript 客戶端簽名直傳

JavaScript 客戶端簽名直傳
JavaScript 客戶端簽名直傳

OSS 的 PostObject API 細節(jié)可以參照這里

關鍵代碼

只要將 plupload 發(fā)送 POST 請求時,帶上 OSS 簽名即可。

var uploader = new plupload.Uploader({
    runtimes: 'html5',
    browse_button: 'selectfiles',
    container: document.getElementById('container'),
    url: host,
    multipart_params: {
        'Filename': '${filename}',
        'key': '${filename}',
        'policy': policyBase64,
        'OSSAccessKeyId': accessid,
        'success_action_status': '200',
        'signature': signature
    },
})

在這里有一點請注意一下,就是 'Filename': '${filename}', 這一段代碼的作用是表示上傳后保持原來的文件文字。如果您想上傳到特定目錄如abc下,文件名保持成原來的文件名,那么應該這樣寫:

// ...
'Filename': 'abc/' + '${filename}',
// ...

有時候要把用戶上傳的文件,設置成隨機文件名,后綴保持跟客戶端文件一致。如果想在上傳時就固定設置成隨機文件名,可以將函數(shù)改成如下:

function check_object_radio(){
    g_object_name_type = 'random_name';
}

如果想固定設置成用戶的文件,可以將函數(shù)改成:

function check_object_radio() {
    g_object_name_type = 'local_name';
}

進階篇:應用服務器 php 返回簽名

采用 JS 客戶端直接簽名有一個很嚴重的安全隱患。就是 OSS AccessId/AccessKey 暴露在前端頁面。可以隨意拿到 AccessId/AccessKey,這是非常不安全的做法。 本小節(jié)將此例子進化,簽名及上傳 policy 從后端 php 代碼取。

請求邏輯是:

  1. 客戶端要上傳圖片時,到應用服務器取上傳的 policy 及簽名。
  2. 客戶端拿到簽名直接上傳到 OSS。
服務器簽名后直傳
服務器簽名后直傳

獲取上傳后的文件名

如果要知道文件上傳成功后的文件名,pupload 會調用 FileUploaded 事件。 如下:

FileUploaded: function(up, file, info){
    var item = document.getElementById(file.id).getElementsByTagName('b')[0];
    if (info.status == 200) {
        item.innerHTML = 'upload to oss success, object name: ' + get_uploaded_object_name(file.name);
    } else {
        item.innerHTML = info.response;
    }
}

上傳簽名

javaScript 最主要是從后端取到 policyBase64accessid、signature 這三個變量。 往后端取這三個變量核心代碼如下:

phpUrl = './php/get.php';
xmlhttp.open( "GET", phpUrl, false );
xmlhttp.send( null );
var obj = eval ("(" + xmlhttp.responseText+ ")");
host = obj['host']
policyBase64 = obj['policy']
accessid = obj['accessid']
signature = obj['signature']
expire = parseInt(obj['expire'])
key = obj['dir']

現(xiàn)在解析一下 xmlhttp.responseText(以下僅為示例,并不一定要求是以下的格式,但是必須有signature、accessid、policy這三個值)。

{
    "accessid":"6MKOqxGiGU4AUk44",
    "host":"http://post-test.oss-cn-hangzhou.aliyuncs.com",
    "policy":"eyJleHBpcmF0aW9uIjoiMjAxNS0xMS0wNVQyMDoyMzoyM1oiLCJjxb25kaXRpb25zIjpbWyJjcb250ZW50LWxlbmd0aC1yYW5nZSIsMCwxMDQ4NTc2MDAwXSxbInN0YXJ0cy13aXRoIiwiJGtleSIsInVzZXItZGlyXC8iXV19",
    "signature":"I2u57FWjTKqX/AE6doIdyff151E=",
    "expire":1446726203,
    "dir":"user-dir/"
}
  • accessid: 指的用戶請求的accessid。注意僅知道accessid, 對數(shù)據不會有影響。
  • host: 指的是用戶要往哪個域名發(fā)往上傳請求。
  • policy:指的是用戶表單上傳的策略policy,是經過base64編碼過的字符串。
  • signature:是對上述第三個變量policy簽名后的字符串。
  • expire:指的是當前上傳策略失效時間,這個變量并不會發(fā)送到OSS,因為這個已經指定在policy里面。

現(xiàn)在分析一下policy的內容,將其解碼后的內容是:

{
    "expiration":"2015-11-05T20:23:23Z",
    "conditions":[
        ["content-length-range",0,1048576000],
        ["starts-with","$key","user-dir/"]
    ]
}

這里有一個關鍵的地方,PolicyText 指定了該 Policy 上傳失效的最終時間。即在這個失效時間之前,都可以利用這個 policy 上傳文件,所以沒有必要每次上傳,都去后端取簽名。為了減少后端的壓力,這里的設計思路是:初始化上傳時,每上傳一個文件后,取一次簽名。然后再上傳時,將當前時間跟簽名時間對比,看簽名時間是否失效了。如果失效了,就重新取一次簽名,如果沒有失效就不取。這里就用到了變量 expire。核心代碼如下:

now = timestamp = Date.parse(new Date()) / 1000;
//可以判斷當前expire是否超過了當前時間,如果超過了當前時間,就重新取一下,3s 做為緩沖[/color]
if (expire < now + 3){
    // ...
    phpUrl = './php/get.php'
    xmlhttp.open( "GET", phpUrl, false );
    xmlhttp.send( null );
    // ...
}

終極篇:應用服務器 php 返回簽名及采用上傳回調

當采用服務端簽名后直傳方案后,問題來了,用戶上傳數(shù)據后,很多場景下,應用服務器都要知道用戶上傳了哪些文件,文件名字,甚至如果是圖片的話,圖片的大小等。為此OSS開發(fā)了上傳回調功能。

用戶的請求邏輯

  1. 用戶向應用服務器取到上傳 policy 和回調設置。
  2. 應用服務器返回上傳 policy 和回調。
  3. 用戶直接向 OSS 發(fā)送文件上傳請求。
  4. 等文件數(shù)據上傳完,OSS 給用戶 Response 前,OSS 會根據用戶的回調設置,請求用戶的服務器。
  5. 如果應用服務器返回成功,那么就返回用戶成功,如果應用服務器返回失敗,那么 OSS 也返回給用戶失敗。這樣確保了用戶上傳成功的照片,應用服務器都已經收到通知了。
  6. 應用服務器給 OSS 返回。
  7. OSS 將應用服務器返回的內容返回給用戶。
服務端簽名直傳并設置上傳回調
服務端簽名直傳并設置上傳回調
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容