在做微信开发时,我需要将图片上传至阿里云OSS,思路是服务端下载微信图片再转存至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();}});}});
选择图片时只要选择了compressed,微信就会自动帮我们压缩图片,官方文档也说明上传的多媒体文件会控制格式和大小,其中图片控制在jpg格式和1M以下的大小。所以,基本不用考虑图片过大的问题。实测中,8M的图片压缩后只有120KB左右。
将图片先上传至微信的服务器(最多保存3天),再通过微信的下载多媒体文件接(http://file.api.…)将图片下载到服务器,再上传至OSS(虽然有点绕,但可行)。
主要有三种方法处理
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('上传文件出错');});});