React實現阿里雲OSS上傳檔案的示例
簡介
阿里雲 OSS 是 阿里雲提供的海量、安全、低成本、高可靠的雲端儲存服務,提供 99.9999999999%的資料可靠性(號稱)。能夠使用 RESTful API 可以在網際網路任何位置儲存和訪問,支援容量和處理能力彈性擴充套件。
基本術語
1.bucket :類似本地的一個資料夾
2.object : oss 儲存資料的基本單元,類似本地的一個檔案。
3.region:oss 儲存的資料中心所在區域
4.Endpoint:oss 對外服務的訪問域名,oss 以 http api 提供服務,不同 region 的 edpoint 不同。
5.AccessKey:訪問祕鑰,簡稱 AK,包括 AccessKeyId 和 AccessKeySecret,用於驗證訪問者身份。後者必須保密
跨域 CROS 設定
進入 控制檯-》基本設定-》跨域-》新增 彈出對話方塊以後填入來源:域名和埠資訊。我們如果使用類似之前 Azure 中 blob 網頁直接上傳的伺服器的方式時需要配置跨域,域名和埠繫結我們的不同環境對應的域名和埠
OSS 操作
建立檔案存放位置
進入控制檯-》建立 bucket -》填寫配置 -》完成
控制檯上傳下載(簡單測試)
檔案管理-》建立目錄 -》上傳檔案
生成 AccessKey 及 AccessSecrect
點選頭像 -》AccessKey 管理 -》開始使用子使用者 Key -》填寫子使用者名稱,勾選程式設計訪問,確定 -》驗證碼接受填寫,確定 -》得到 key 和 Secret -》許可權管理-》授權 -》新增管理物件儲存 OSS 許可權
注意:這裡必須使用子使用者的 key,如果用主賬號容易導致提交程式碼時的許可權洩露,一旦 key 和 secret 洩露相當於賬號密碼洩露,伺服器就完全暴露給了別人。
API 操作
實際專案中並不是依靠在控制檯手工操作,而是利用程式來控制上傳下載。OSS 提供了一系列的 restful API 來實現檔案上傳於下載。
可以利用阿里雲提供的 SDK 簡化實現。具體見下文。
前端上傳檔案程式開發
基本流程
在實際專案中,一般採用分散式及微服務的 web 業務系統中,檔案的上傳和下載都是直接在前端來實現對 oss 的操作。也就是前端直接上傳,不通過自己的伺服器。這樣能夠實現系統無阻礙的橫向擴充套件。另一個原因是如果要把檔案儲存在執行 web 伺服器的同一臺伺服器上時,那麼在檔案上傳時可能會佔滿頻寬,影響 web 的訪問。分開儲存不佔伺服器頻寬。
阿里 OSS 提供了三種前端直傳方式:
1.瀏覽器簽名後直接上傳 OSS(無需服務端干預)
2.瀏覽器請求伺服器簽名地址後上傳(需要服務端配合)
3.瀏覽器請求伺服器簽名地址後上傳並回調服務端(需要服務端配合)
實際生產環境考慮到安全性必須選擇第二種,需要服務端與前端相配合,當安全性要求不高時可採用第一種方式。分別如下。
方式 1:前端直傳(無須服務端干預)
為保證檔案的安全性,一般設定 bucket 為私有,也就是鑑權以後的使用者才能訪問 OSS 中的內容。前端直傳的原理是在瀏覽器端根據 OSS 控制檯提供的 AccessId 和 AccessSecret 生成簽名直接上傳,不需要經過服務端,優點是使用簡單,缺點是不安全。
React 搭配 antd 中 upload 元件實現如下:
upload 元件提供了 beforeUpload
鉤子函式,在執行向 OSSpost 檔案前我們先在本地計算好 OSS 要求的簽名,如下:
beforeUpload = async () => { const { OSSData } = this.state; const expire = OSSData.expire * 1000; if (expire < Date.now()) { await this.init(); } return true; }; init = async () => { try { const OSSData = await this.mockGetOSSData(); this.setState({ OSSData,}); } catch (error) { message.error(error); } }; mockGetOSSData = () => { var policyText = { expiration: "2020-12-01T12:00:00.000Z",//設定該Policy的失效時間,超過這個失效時間之後,就沒有辦法通過這個policy上傳檔案了 conditions: [ ["content-length-range",1048576000],// 設定上傳檔案的大小限制 ],}; let accesskey = "你自己的"; //不要洩露 var policyBase64 = Base64.encode(JSON.stringify(policyText)); let message = policyBase64; var bytes = Crypto.HMAC(Crypto.SHA1,message,accesskey,{ asBytes: true }); var signature = Crypto.util.bytesToBase64(bytes); return { dir: "user-dir/",//bucket中的路徑 expire: "0",//有效時間戳'1577811661',host: "http://om-test-oss.oss-cn-beijing.aliyuncs.com",accessId: "你自己的",policy: policyBase64,//you signature: signature,}; };
鉤子函式首先計算簽名是否過期,如果過期則通過init
函式間接呼叫mockGetOSSData
生成通過 Base64 等 OSS 要求方法生成簽名資料。其中accessId
與accesskey
是從 OSS 控制檯拿到的。
生成簽名資料後,利用upload
元件中action
props 直接將檔案上傳目的地指向 OSS 的實際有效地址,並進行上傳
render() { const { value } = this.props; const props = { name: 'file',listType: "picture-card",fileList: value,action: this.state.OSSData.host,onChange: this.onChange,onRemove: this.onRemove,transformFile: this.transformFile,data: this.getExtraData,beforeUpload: this.beforeUpload,}; return ( <Upload {...props}> <Icon type="plus" /> </Upload> ); }
完整程式碼如下:
render() { const { value } = this.props; const props = { name: 'file',}; return ( <Upload {...props}> <Icon type="plus" /> </Upload> ); }
方式 2:前端與後端配合上傳
後端鑑權介面
後端需要增加一個介面:後端利用阿里提供的 SDK,編寫鑑權介面,入參是要上傳的檔案內容,根據控制檯得到的 endpoint、AccessKey 和 AccessSecret 例項化 client,每次前端上傳檔案前請求本介面,服務端與阿里雲 OSS 互動,根據 bucket 拿到簽名後的上傳、下載地址(過程中可以設定上傳下載的有效期以及 Conetent-Type),將兩者以及檔名返回給前端,用於前端的下一步操作。
前端分別請求
前端然後根據後端鑑權介面返回簽名後的 puturl 採用 put 方式上傳圖片檔案。在前端 put 上傳圖片成功後可以通過 geturl 拿到圖片來進行網頁回顯,回顯同時將圖片名稱插入到要提交表單中,最後點選提交按鈕將圖片路徑等資訊 post 到自己後端另一個介面中,後端儲存到資料庫。
前端程式與上文中的方式 1 大同小異,唯一不同在於mockGetOSSData
函式,之前是由前端計算簽名,這裡是呼叫後端的鑑權介面來獲得簽名資料。
**注意:**最後一個介面呼叫中檔名稱只有後半部分,前半部分路徑是 OSS 提供的 bucket 路徑,完全相同,再次展示時前端自行拼接。
上傳中途失敗處理
上述前端直傳流程至少呼叫三個介面:鑑權、上傳、儲存。如果在上傳檔案後沒有呼叫儲存介面,也就是應用服務沒有把 OSS 中檔案關聯到資料庫中時會造成 OSSbucket 中有髒資料的情況,解決辦法是:先讓使用者上傳到一個臨時的資料夾中,當呼叫儲存介面後再移動到真正的 bucket 中,然後定時刪除臨時資料夾。
前端下載檔案程式開發
與上傳類似,OSS 也支援瀏覽器下載,在 bucket 的讀寫許可權設定為私有後,讀寫均需簽名才可以。舉例如下:
如果上傳圖片到 OSS 成功後,得到的圖片 url 是user-dir/1580982085120.png
,如果直接拼接 OSS 前半部分為http://om-test-oss.oss-cn-beijing.aliyuncs.com/user-dir/1580982085120.png
訪問會提示失敗,因為 OSS 有判斷沒有簽名信息會拒絕訪問,真正的簽名後的圖片地址是:http://om-test-oss.oss-cn-beijing.aliyuncs.com/user-dir/1580982085120.png?OSSAccessKeyId=LTAI4Fv75GobJhGFkwVzdPJq&Expires=1580983892&Signature=FZYmRRo6XnFu3INC55zJSdTWT%2Fc%3D
我們要做的就是得到簽名後的下載地址。下載與上傳相同,也分為是否需要伺服器參與的兩種方式。
方式 1:前端簽名直接下載
前端簽名與上傳類似,根據 AccessId 與 AccessSecret 來生成簽名信息。
簽名信息可以在請求攜帶在 URL 中也可以攜帶在請求 header 中,為方便使用,此次調研使用前者。
本地簽名使用了 OSS 提供的 SDK,react 首先安裝
npm install ali-oss --save
然後在元件中引入
import OSS from "ali-oss";
封裝 SDK 的簽名方法簡化使用
import React,{ Component } from "react"; import OSS from "ali-oss"; let GetOssfileClient = new OSS({ region: "oss-cn-beijing",//oss所在region,由運維提供 accessKeyId: "你自己的",//oss的子accessKeyId,由運維提供 accessKeySecret: "你自己的",//oss的子accessKeySecret,由運維提供 bucket: "om-test-oss",//oss的buket名稱,運維提供 }); export default GetOssfileClient;
上傳元件的預覽功能使用到了圖片下載如下:
//預覽可以使用本地圖片也可以使用上傳到oss真實圖片,這裡使用真實地址用來測試對oss的訪問 handlePreview = (file) => { //file中thumbUrl是本地生成的,url是OSS檔名部分,需要簽名後才能訪問 console.log("替換前的 file.url",file.url); let url = GetOssfileClient.signatureUrl(file.url); console.log(url); file.url = url; //替換為簽名後的真實路徑, console.log("替換後的 file.url,也就是真實地址是:",file.url); this.setState({ previewImage: file.url || file.thumbUrl,previewVisible: true,}); };
這裡使用 upload 元件預覽功能來測試圖片的下載顯示。當點選預覽觸圖示時會觸發handlePreview
函式,我們拿到真實圖片檔案的檔名,然後使用 sdk 的signatureUrl
方法簽名後得到真實路徑,然後在 modal 中顯示。
<Modal visible={previewVisible} footer={null} onCancel={this.handleCancel}> <img alt="example" style={{ width: "100%" }} src={previewImage} /> </Modal>
方式 2:前端根據後端返回的連線下載
同上述前端上傳檔案程式開發->方式2
,前端直接使用後端程式碼返回的 url 來顯示圖片即可,後端返回的 url 已經是簽名後的完整路徑了。
安全起見,最好使用前後端配置上傳下載
到此這篇關於React實現阿里雲OSS上傳檔案的示例的文章就介紹到這了,更多相關React 阿里雲OSS上傳內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!