2000字范文,分享全网优秀范文,学习好帮手!
2000字范文 > 微信公众号图片上传至阿里云OSS

微信公众号图片上传至阿里云OSS

时间:2024-07-19 09:15:56

相关推荐

微信公众号图片上传至阿里云OSS

最近在做微信公众号,需要将图片上传至阿里云OSS。在做这个功能的过程中,我走了不少弯路,尝试过很多种方法,最后终于研究出一种便捷优美的方式。现在把这些方法和思路记录下来,避免遗忘。

一、通过浏览器直接传给OSS

这种方式最简单。因为微信公众号的跳转页面是基于QQ浏览器的,所以可以直接使用HTML的input元素选择图片。

<input type="file", name="pic", accept="image/jpeg" />

OSS有一个Post Object的接口允许HTML表单上传文件,除了文件(file)之外,还有一些其他的字段如保存到OSS的路径(key)、策略(policy)、自己的OSS应用的accessKeyId、签名(signature)等。

所以需要构造表单。一般有两种方式:

1)构造DOM节点,表单提交上传

像下面代码这样构造form元素,然后利用$('form').submit()提交。

<!-- 请求地址由bucket名和oss的区域构成 --><form method="POST" action="http://bucketname.oss-cn-"><input type="hidden" name="key" /><input type="hidden" name="policy" /><input type="hidden" name="OSSAccessKeyId" /><input type="hidden" name="success_action_status" /> <input type="hidden" name="signature" /><input type="file" name="file" accept="image/jpeg" /></form>

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, // 默认9sizeType: ['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./cgi-bin/media/get?access_token=ACCESS_TOKEN&media_id=MEDIA_ID)将图片下载到服务器,再上传至OSS(虽然有点绕,但可行)。

客户端代码:

wx.chooseImage({count: 1, // 默认9sizeType: ['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'; // 微信多媒体文件idconst destPath = `weixin/images/02/${mediaId}.jpg`; // OSS文件路径,按自己喜欢构造咯const wxReq = request(`http://file.api./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'; // 微信多媒体文件idconst destPath = `weixin/images/02/${mediaId}.jpg`; // OSS文件路径const writer = new streams.WritableStream();const wxReq = request(`http://file.api./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'; // 微信多媒体文件idconst destPath = `weixin/images/02/${mediaId}.jpg`; // OSS文件路径const wxReq = request(`http://file.api./cgi-bin/media/get?access_token=${accessToken }&media_id=${mediaId}`);wxReq.on('response', (response) => {// request的响应结果response可以作为读取流传给ossClientco(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('上传文件出错');});});

这种方式省去了前面两种方式的中间步骤,更加简练直接,个人认为是最好的。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。