摘要:最近在做微信公眾號,需要將圖片上傳至阿里云。利用模塊將圖片寫到內存微信多媒體文件文件路徑圖片上傳阿里云結果上傳文件出錯這種方式將圖片暫存在內存里面,那如果并發量很大,是不是內存要爆炸了都感覺還是不可取。
最近在做微信公眾號,需要將圖片上傳至阿里云OSS。在做這個功能的過程中,我走了不少彎路,嘗試過很多種方法,最后終于研究出一種便捷優美的方式。現在把這些方法和思路記錄下來,避免遺忘。
一、通過瀏覽器直接傳給OSS這種方式最簡單。因為微信公眾號的跳轉頁面是基于QQ瀏覽器的,所以可以直接使用HTML的input元素選擇圖片。
OSS有一個Post Object的接口允許HTML表單上傳文件,除了文件(file)之外,還有一些其他的字段如保存到OSS的路徑(key)、策略(policy)、自己的OSS應用的accessKeyId、簽名(signature)等。
所以需要構造表單。一般有兩種方式:
1)構造DOM節點,表單提交上傳像下面代碼這樣構造form元素,然后利用$("form").submit()提交。
2)利用Html5的FormData對象上傳
像下面這樣構造FormData對象,再通過ajax或fetch post表單數據。
const formData = new FormData(); formData.append("key", filePath); // OSS的保存路徑 formData.append("policy", policy); // 策略 formData.append("OSSAccessKeyId", accessKeyId); // OSS對象的標識 formData.append("success_action_status", "200"); // 成功返回碼 formData.append("signature", signature); // 簽名 formData.append("file", file); // 圖片文件,$("input[name="pic"]").files[0]二、服務端下載微信圖片再轉存至OSS
上面的方法雖然簡單直接,但只能從相冊中選擇圖片,而想要拍攝圖片并上傳,則必須通過微信JS-SDK來調用相機。
wx.chooseImage({ count: 1, // 默認9 sizeType: ["original", "compressed"], // 可以指定是原圖還是壓縮圖,默認二者都有 sourceType: ["album", "camera"], // 可以指定來源是相冊還是相機,默認二者都有 success: function (res) { // 返回選定照片的本地ID列表,localId可以作為img標簽的src屬性顯示圖片 var localIds = res.localIds; } });
這里有個問題,微信JS-SDK選擇圖片之后返回的是圖片的標識id,而不是實際的圖片文件,所以不能構造form表單上傳OSS。
那該怎么辦呢?思路:將圖片先上傳至微信的服務器(最多保存3天),再通過微信的下載多媒體文件接口(http://file.api.weixin.qq.com...)將圖片下載到服務器,再上傳至OSS(雖然有點繞,但可行)。
客戶端代碼:
wx.chooseImage({ count: 1, // 默認9 sizeType: ["original", "compressed"], sourceType: ["album", "camera"], success: function (res) { var localIds = res.localIds; wx.uploadImage({ localId: localIds[0], // 需要上傳的圖片的本地ID,由chooseImage接口獲得 isShowProgressTips: 1, // 默認為1,顯示進度提示 success: function (res) { var serverId = res.serverId; // 返回圖片的服務器端ID // do something ... // 調用自己搭建的服務端的api,傳入serverId,做獲取微信圖片上傳OSS的相關操作 doSomething(); } }); } });
小tips:選擇圖片時只要選擇了compressed,微信就會自動幫我們壓縮圖片,官方文檔也說明上傳的多媒體文件會控制格式和大小,其中圖片控制在jpg格式和1M以下的大小。所以,基本不用考慮圖片過大的問題。實測中,8M的圖片壓縮后只有120KB左右。
服務端的代碼經過了3次的演變才完善:
1)利用fs將圖片寫到本地const fs = require("fs"); const request = require("require"); const OSS = require("ali-oss").Wrapper; const ossClient = new OSS({ accessKeyId: "your access key", accessKeySecret: "your access secret", bucket: "your bucket name", region: "oss-cn-hangzhou" }); // 需要獲取微信accessToken,這里不細說 const accessToken = "access token"; const mediaId = "xxxxxxx"; // 微信多媒體文件id const destPath = `weixin/images/201702/${mediaId}.jpg`; // OSS文件路徑,按自己喜歡構造咯 const wxReq = request(`http://file.api.weixin.qq.com/cgi-bin/media/get?access_token=${accessToken }&media_id=${mediaId}`); // 將文件流pipe到本地文件 wxReq.pipe(fs.createWriteStream(`${mediaId}.jpg`)); wxReq.on("end", () => { co(function* () { const result = yield ossClient.putStream(destPath, fs.createReadStream(`${mediaId}.jpg`), {timeout: 30 * 60 * 1000}); console.log("圖片上傳阿里云結果", result); fs.unlink(`${mediaId}.jpg`); // res.status(200).json(result); }).catch(err => { console.warn(err); //res.status(500).send("上傳文件出錯"); }); });
這種方式需要頻繁地寫文件和刪文件,感覺一點都不極客。
2)利用memory-streams模塊將圖片寫到內存const request = require("require"); const OSS = require("ali-oss").Wrapper; const streams = require("memory-streams"); const ossClient = new OSS({ accessKeyId: "your access key", accessKeySecret: "your access secret", bucket: "your bucket name", region: "oss-cn-hangzhou" }); const accessToken = "access token"; const mediaId = "xxxxxxx"; // 微信多媒體文件id const destPath = `weixin/images/201702/${mediaId}.jpg`; // OSS文件路徑 const writer = new streams.WritableStream(); const wxReq = request(`http://file.api.weixin.qq.com/cgi-bin/media/get?access_token=${accessToken }&media_id=${mediaId}`); wxReq.pipe(writer); wxReq.on("end", () => { co(function* () { const result = yield ossClient.put(destPath, writer.toBuffer(), {timeout: 30 * 60 * 1000}); console.log("圖片上傳阿里云結果", result); // res.status(200).json(result); }).catch(err => { console.warn(err); //res.status(500).send("上傳文件出錯"); }); });
這種方式將圖片暫存在內存里面,那如果并發量很大,是不是內存要爆炸了都?感覺還是不可取。
3)將下載圖片的流直接寫入OSS文件折騰了好久,發現原來可以這么簡單和優雅:
const request = require("require"); const OSS = require("ali-oss").Wrapper; const ossClient = new OSS({ accessKeyId: "your access key", accessKeySecret: "your access secret", bucket: "your bucket name", region: "oss-cn-hangzhou" }); const accessToken = "access token"; const mediaId = "xxxxxxx"; // 微信多媒體文件id const destPath = `weixin/images/201702/${mediaId}.jpg`; // OSS文件路徑 const wxReq = request(`http://file.api.weixin.qq.com/cgi-bin/media/get?access_token=${accessToken }&media_id=${mediaId}`); wxReq.on("response", (response) => { // request的響應結果response可以作為讀取流傳給ossClient co(function* () { const result = yield ossClient.putStream(destPath, response, {timeout: 30 * 60 * 1000}); console.log("圖片上傳阿里云結果", result); // res.status(200).json(result); }).catch(err => { console.warn(err); //res.status(500).send("上傳文件出錯"); }); });
這種方式省去了前面兩種方式的中間步驟,更加簡練直接,個人認為是最好的。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/81513.html
摘要:一準備工作開通阿里云服務,從控制臺上獲取和。參考資料阿里云官方文檔開始使用阿里云官方文檔介紹如何在中快速使用訪問服務微信公眾號圖片上傳至阿里云前端圖片直傳試驗如何基于和,快速搭建音視頻文件上傳服務聲明轉發請注明出處,謝謝 一、準備工作 1. 開通阿里云OSS服務,從控制臺上獲取AccessKeyId和AccessKeySecret。 2. 創建Bucket,并登錄OSS控制臺 3. 配...
摘要:筆主很早就開始用阿里云存儲服務當做自己的圖床了。阿里云對象存儲文檔,本篇文章會介紹到整合阿里云存儲服務實現文件上傳下載以及簡單的查看。 Github 地址:https://github.com/Snailclimb/springboot-integration-examples(SpringBoot和其他常用技術的整合,可能是你遇到的講解最詳細的學習案例,力爭新手也能看懂并且能夠在看完...
摘要:接下來講解一下博客中用的圖床阿里云對象存儲,簡稱,雖然目前大家用的比較多的是七牛云之類的,但是因為我個人原因我還是選擇了阿里云,后面我會簡單說明下原因。 showImg(https://segmentfault.com/img/remote/1460000008838754?w=960&h=300); 前言 之前打算寫一篇有關個人博客SEO優化的體驗和一些自身體會,但是發現自己還沒完全...
閱讀 4293·2021-09-24 09:47
閱讀 1184·2021-09-03 10:33
閱讀 2063·2019-08-30 11:13
閱讀 1029·2019-08-30 10:49
閱讀 1753·2019-08-29 16:13
閱讀 2046·2019-08-29 11:28
閱讀 3089·2019-08-26 13:31
閱讀 3631·2019-08-23 17:14