React實現(xiàn)阿里云OSS上傳文件的示例
簡介
阿里云 OSS 是 阿里云提供的海量、安全、低成本、高可靠的云存儲服務(wù),提供 99.9999999999%的數(shù)據(jù)可靠性(號稱)。能夠使用 RESTful API 可以在互聯(lián)網(wǎng)任何位置存儲和訪問,支持容量和處理能力彈性擴展。
基本術(shù)語
1.bucket :類似本地的一個文件夾
2.object : oss 存儲數(shù)據(jù)的基本單元,類似本地的一個文件。
3.region:oss 存儲的數(shù)據(jù)中心所在區(qū)域
4.Endpoint:oss 對外服務(wù)的訪問域名,oss 以 http api 提供服務(wù),不同 region 的 edpoint 不同。
5.AccessKey:訪問秘鑰,簡稱 AK,包括 AccessKeyId 和 AccessKeySecret,用于驗證訪問者身份。后者必須保密
跨域 CROS 設(shè)置
進入 控制臺-》基本設(shè)置-》跨域-》新增 彈出對話框以后填入來源:域名和端口信息。我們?nèi)绻褂妙愃浦?Azure 中 blob 網(wǎng)頁直接上傳的服務(wù)器的方式時需要配置跨域,域名和端口綁定我們的不同環(huán)境對應(yīng)的域名和端口
OSS 操作
創(chuàng)建文件存放位置
進入控制臺-》創(chuàng)建 bucket -》填寫配置 -》完成
控制臺上傳下載(簡單測試)
文件管理-》創(chuàng)建目錄 -》上傳文件
生成 AccessKey 及 AccessSecrect
點擊頭像 -》AccessKey 管理 -》開始使用子用戶 Key -》填寫子用戶名,勾選編程訪問,確定 -》驗證碼接受填寫,確定 -》得到 key 和 Secret -》權(quán)限管理-》授權(quán) -》新增管理對象存儲 OSS 權(quán)限
注意:這里必須使用子用戶的 key,如果用主賬號容易導(dǎo)致提交代碼時的權(quán)限泄露,一旦 key 和 secret 泄露相當(dāng)于賬號密碼泄露,服務(wù)器就完全暴露給了別人。
API 操作
實際項目中并不是依靠在控制臺手工操作,而是利用程序來控制上傳下載。OSS 提供了一系列的 restful API 來實現(xiàn)文件上傳于下載。
可以利用阿里云提供的 SDK 簡化實現(xiàn)。具體見下文。
前端上傳文件程序開發(fā)
基本流程
在實際項目中,一般采用分布式及微服務(wù)的 web 業(yè)務(wù)系統(tǒng)中,文件的上傳和下載都是直接在前端來實現(xiàn)對 oss 的操作。也就是前端直接上傳,不通過自己的服務(wù)器。這樣能夠?qū)崿F(xiàn)系統(tǒng)無阻礙的橫向擴展。另一個原因是如果要把文件保存在運行 web 服務(wù)器的同一臺服務(wù)器上時,那么在文件上傳時可能會占滿帶寬,影響 web 的訪問。分開存儲不占服務(wù)器帶寬。
阿里 OSS 提供了三種前端直傳方式:
1.瀏覽器簽名后直接上傳 OSS(無需服務(wù)端干預(yù))
2.瀏覽器請求服務(wù)器簽名地址后上傳(需要服務(wù)端配合)
3.瀏覽器請求服務(wù)器簽名地址后上傳并回調(diào)服務(wù)端(需要服務(wù)端配合)
實際生產(chǎn)環(huán)境考慮到安全性必須選擇第二種,需要服務(wù)端與前端相配合,當(dāng)安全性要求不高時可采用第一種方式。分別如下。
方式 1:前端直傳(無須服務(wù)端干預(yù))
為保證文件的安全性,一般設(shè)置 bucket 為私有,也就是鑒權(quán)以后的用戶才能訪問 OSS 中的內(nèi)容。前端直傳的原理是在瀏覽器端根據(jù) OSS 控制臺提供的 AccessId 和 AccessSecret 生成簽名直接上傳,不需要經(jīng)過服務(wù)端,優(yōu)點是使用簡單,缺點是不安全。
React 搭配 antd 中 upload 組件實現(xiàn)如下:
upload 組件提供了 beforeUpload
鉤子函數(shù),在執(zhí)行向 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", //設(shè)置該Policy的失效時間,超過這個失效時間之后,就沒有辦法通過這個policy上傳文件了 conditions: [ ["content-length-range", 0, 1048576000], // 設(shè)置上傳文件的大小限制 ], }; 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, }; };
鉤子函數(shù)首先計算簽名是否過期,如果過期則通過init
函數(shù)間接調(diào)用mockGetOSSData
生成通過 Base64 等 OSS 要求方法生成簽名數(shù)據(jù)。其中accessId
與accesskey
是從 OSS 控制臺拿到的。
生成簽名數(shù)據(jù)后,利用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', 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> ); }
方式 2:前端與后端配合上傳
后端鑒權(quán)接口
后端需要增加一個接口:后端利用阿里提供的 SDK,編寫鑒權(quán)接口,入?yún)⑹且蟼鞯奈募?nèi)容,根據(jù)控制臺得到的 endpoint、AccessKey 和 AccessSecret 實例化 client,每次前端上傳文件前請求本接口,服務(wù)端與阿里云 OSS 交互,根據(jù) bucket 拿到簽名后的上傳、下載地址(過程中可以設(shè)置上傳下載的有效期以及 Conetent-Type),將兩者以及文件名返回給前端,用于前端的下一步操作。
前端分別請求
前端然后根據(jù)后端鑒權(quán)接口返回簽名后的 puturl 采用 put 方式上傳圖片文件。在前端 put 上傳圖片成功后可以通過 geturl 拿到圖片來進行網(wǎng)頁回顯,回顯同時將圖片名稱插入到要提交表單中,最后點擊提交按鈕將圖片路徑等信息 post 到自己后端另一個接口中,后端保存到數(shù)據(jù)庫。
前端程序與上文中的方式 1 大同小異,唯一不同在于mockGetOSSData
函數(shù),之前是由前端計算簽名,這里是調(diào)用后端的鑒權(quán)接口來獲得簽名數(shù)據(jù)。
**注意:**最后一個接口調(diào)用中文件名稱只有后半部分,前半部分路徑是 OSS 提供的 bucket 路徑,完全相同,再次展示時前端自行拼接。
上傳中途失敗處理
上述前端直傳流程至少調(diào)用三個接口:鑒權(quán)、上傳、保存。如果在上傳文件后沒有調(diào)用保存接口,也就是應(yīng)用服務(wù)沒有把 OSS 中文件關(guān)聯(lián)到數(shù)據(jù)庫中時會造成 OSSbucket 中有臟數(shù)據(jù)的情況,解決辦法是:先讓用戶上傳到一個臨時的文件夾中,當(dāng)調(diào)用保存接口后再移動到真正的 bucket 中,然后定時刪除臨時文件夾。
前端下載文件程序開發(fā)
與上傳類似,OSS 也支持瀏覽器下載,在 bucket 的讀寫權(quán)限設(shè)置為私有后,讀寫均需簽名才可以。舉例如下:
如果上傳圖片到 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
我們要做的就是得到簽名后的下載地址。下載與上傳相同,也分為是否需要服務(wù)器參與的兩種方式。
方式 1:前端簽名直接下載
前端簽名與上傳類似,根據(jù) AccessId 與 AccessSecret 來生成簽名信息。
簽名信息可以在請求攜帶在 URL 中也可以攜帶在請求 header 中,為方便使用,此次調(diào)研使用前者。
本地簽名使用了 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;
上傳組件的預(yù)覽功能使用到了圖片下載如下:
//預(yù)覽可以使用本地圖片也可以使用上傳到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 組件預(yù)覽功能來測試圖片的下載顯示。當(dāng)點擊預(yù)覽觸圖標(biāo)時會觸發(fā)handlePreview
函數(shù),我們拿到真實圖片文件的文件名,然后使用 sdk 的signatureUrl
方法簽名后得到真實路徑,然后在 modal 中顯示。
<Modal visible={previewVisible} footer={null} onCancel={this.handleCancel}> <img alt="example" style={{ width: "100%" }} src={previewImage} /> </Modal>
方式 2:前端根據(jù)后端返回的連接下載
同上述前端上傳文件程序開發(fā)->方式2
,前端直接使用后端代碼返回的 url 來顯示圖片即可,后端返回的 url 已經(jīng)是簽名后的完整路徑了。
安全起見,最好使用前后端配置上傳下載
到此這篇關(guān)于React實現(xiàn)阿里云OSS上傳文件的示例的文章就介紹到這了,更多相關(guān)React 阿里云OSS上傳內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
基于visual studio code + react 開發(fā)環(huán)境搭建過程
今天通過本文給大家分享基于visual studio code + react 開發(fā)環(huán)境搭建過程,本文給大家介紹的非常詳細,包括react安裝問題及安裝 Debugger for Chrome的方法,需要的朋友跟隨小編一起看看吧2021-07-07React學(xué)習(xí)筆記之高階組件應(yīng)用
這篇文章主要介紹了React 高階組件應(yīng)用,詳細的介紹了什么是React高階組件和具體使用,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-06-06ahooks封裝cookie?localStorage?sessionStorage方法
這篇文章主要為大家介紹了ahooks封裝cookie?localStorage?sessionStorage的方法示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-07-07