上传图片是很常见的需求,方法也有不少。本次使用的是七牛云的对象存储,七牛云的oss作的仍是比较出色的。html
七牛云的上传大致分为两种前端
受权式上传其实还分两种,一种是调用 qiniu SDK,一种直接调用七牛的上传接口node
本文会把两种方法都实现,实际开发根据状况选用ios
formData + axios + koa + koa-bodyshell
这种上传方式,后端只须要返回七牛的 token,由前端调用 SDK 或者 上传接口npm
七牛云的sdk能够经过script标签引入axios
https://unpkg.com/qiniu-js@2.4.0/dist/qiniu.min.js
qiniu
的对象经过npm安装后端
npm install qiniu-js --save
import * as qiniu from 'qiniu-js'
qiniu-sdkapi
主要api,qiniu.upload(file, key, token, putExtra, config)app
调用成功后返回一个observable对象,调用它的 subscribe 方法获取到响应结果
observable.subscribe({ complete(res) { // 上传完成的响应信息,res 包含 hash、key两个属性(默认) }, next(res) { // 接收上传进度信息,res 包含loaded、total、percent三个属性,提供上传进度信息。 }, error(err) { // 上传错误触发,err 包含 code、message、isRequestError 三个属性 } });
前端代码:发送请求使用 axios
<input type="file" id="upload" accept="image/*" />
const fileInput = document.getElementById('upload'); fileInput.addEventListener('change', async function(e) { const file = e.target.files[0]; // Blob,文件流对象 // 经过后端接口获取七牛云的 token const res = await axios.get('/qiniuToken'); const { token, key } = res.data; const putExtra = { fname: '', // 文件原文件名 params: {}, // 用来放置自定义变量 mimeType: null // 用来限制上传文件类型,为 null 时表示不对文件类型限制;eg: ["image/png", "image/jpeg"] }; const config = { useCdnDomain: true, // 开启 cdn 加速域名 region: null, // 为 null 会自动解析上传区域 }; // 调用 qiniu.upload 上传图片,生成 observable 实例 const observable = qiniu.upload(file, key, token, putExtra, config); // 调用 observable 的 subscribe 方法,获取响应结果 observable.subscribe({ complete(data) { const { key } = data; // 把返回的 key 与 域名拼接,就是图片地址 const url = '配置的域名' + key; }, next(res) { // ... }, error(err) { // ... } }); });
首先拿到 token,而后调用上传的 api ,不一样的空间区域对应不一样的接口地址,个人空间是华南区域,接口地址:http://upload-z2.qiniu.com
const fileInput = document.getElementById('upload'); fileInput.addEventListener('change', async function(e) { const file = e.target.files[0]; // Blob,文件流对象 // 经过后端接口获取七牛云的 token const res = await axios.get('/qiniuToken'); const { token, key } = res.data; const formData = new FormData(); formData.append('token', token); formData.append('key', key); // key:文件名,能够不传,若是不传七牛则会自动生成随机文件名 hash formData.append('file', file); const response = await axios.post('http://upload-z2.qiniu.com', formData); const url = '七牛云仓库配置的域名' + response.key; });
上面的两种上传方式,后端须要返回 token
后端代码:后端实现使用 koa
由于只须要返回 token,因此相对简单
const qiniu = require('qiniu') router.get('/qiniuToken', async (ctx) => { // accessKey,secretKey 在我的中心能够查看 const accessKey = 'your access key'; const secretKey = 'your secret key'; // 鉴权对象 mac const mac = new qiniu.auth.digest.Mac(accessKey, secretKey); const options = { scope: 'your bucket' // 仓库名 }; const putPolicy = new qiniu.rs.PutPolicy(options); const token = putPolicy.uploadToken(mac); const key = +new Date() + Math.random().toString(16).slice(2); // key 只须要随机不重复就能够 ctx.body = { status: 1, data: { token, key } }; });
前端只须要传递一个 file 文件流对象
fileInput.addEventListener('change', async function(e) { const file = e.target.files[0]; // Blob,文件流对象 const formData = new FormData(); formData.append('file', formData); // file 是后端接受的字段 // axios 识别到参数为 formData 类型后,会自动修改 Content-Type 为 multipart/form-data const res = await axios.post('/qiniu', formData); const { url } = res.data; });
后端须要调用 qiniu-sdk
先下载 koa-body
npm i -S koa-body
const koaBody = require('koa-body'); const koaBodyOpts = { multipart: true, // 默认不会接受 formData 参数,须要开启 formLimit: '15mb' // 默认 56 kb,尽可能设置大一些 }; // 在全局使用 koa-body app.use(koaBody(koaBodyOpts)); // 在某个路由使用 router.post('/qiniu', koaBody(koaBodyOpts), async (ctx) => { const { file } = ctx.request.body.files; const ext = path.extname(file.name); const fileName = +new Date() + ext; const localFile = file.path; try { const res = await qiniuPut(fileName, localFile); const url = qiniuOpts.url + res.key; ctx.body = { status: 1, data: { url } }; } catch (e) { console.log(e); ctx.body = { status: 0, msg: '上传失败' }; } }); // 获取七牛云 token const qiniuToken = () => { const accessKey = 'your access key'; const secretKey = 'your secret key'; const mac = new qiniu.auth.digest.Mac(accessKey, secretKey); const options = { scope: 'your bucket' }; const putPolicy = new qiniu.rs.PutPolicy(options); const uploadToken = putPolicy.uploadToken(mac); return uploadToken; }; // 七牛云文件上传 const qiniuPut = (key, localFile) => { const uploadToken = qiniuToken(); const config = new qiniu.conf.Config(); // 空间对应的机房 config.zone = qiniu.zone.Zone_z2; const formUploader = new qiniu.form_up.FormUploader(config); const putExtra = new qiniu.form_up.PutExtra(); return new Promise((resolve, reject) => { formUploader.putFile(uploadToken, key, localFile, putExtra, (respErr, respBody, respInfo) => { if (respErr) { reject(respErr); } else { resolve(respBody); } }); }); }
七牛云的 api 还有不少,有兴趣能够看看文档