服务端将图片源传递到七牛,这种方式的流程是javascript
1 前端将图片传到本身的服务器 2 在server将文件传递到七牛html
须要注意,要使用 formData 格式进行文件上传, 关于 formData前端
document.querySelector('input').onchange = () => { const file = document.querySelector('input').files[0] let formData = new FormData() formData.append('file', file) // fetch调用接口 fetch(path, { body: formData, credentials: 'same-origin', method: 'POST' }) } 复制代码
const bucket = 'cancan' const accessKey = '2LC7KPjwnYdxxxc' const secretKey = 'SXrxxx' const domain = 'http://pq3xxxdn.com' 复制代码
function get_token () { const mac = new qiniu.auth.digest.Mac(accessKey, secretKey); const policyParams = { scope: bucket } const putPolicy = new qiniu.rs.PutPolicy(policyParams); const uploadToken = putPolicy.uploadToken(mac); return uploadToken } 复制代码
async function uploadFile(localFile, key) { const uploadToken = get_token() const config = new qiniu.conf.Config(); // 空间对应的机房 config.zone = qiniu.zone.Zone_z0; 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, function (respErr, respBody, respInfo) { if (respErr) { reject('error') } if (respInfo.statusCode == 200) { const { key } = respBody resolve(`${domain}/${key}`) } }); }) } 复制代码
router.post('/upload', async (ctx) => { // 获取到上传到服务器的文件信息 const { img } = ctx.request.files // path 拿到临时文件地址 const { path } = img // key 是给图片的命名 const key = Math.random() * 100 + '.png' const result = await uploadFile(path, key) ctx.body = result }) 复制代码
后来发现是由于 中间件只使用了 koa-bodyparser, 通常图片上传使用的是 koa-multer,可使用 koa-body来代替这两个java
参考文章node
能够看到,在将文件上传到服务器的时候,会建立一个临时文件- 接口中解析的那个 pathwebpack
对于服务器,能够写一个定时的脚本去清除这些文件。或者咱们在脚本增长一段逻辑,在成功上传到七牛以后,手动将临时文件进行删除git
fs.unlink(path, (err) => { if (err) throw err; console.log('文件已删除', path); }) 复制代码
项目中的例子涉及到的图片上传,都是将文件上传到服务器而后再去传到七牛空间,这种操做方式,至关于在本身的服务器作了一层中转站。开发者能够在中转站对图片作一些处理而后在传到七牛空间。可是有一些缺点github
内存占用量增大web
临时文件占用磁盘空间,须要每次上传以后须要进行文件删除npm
若是开发中不须要中转站,能够考虑直接从前端将图片上传到七牛空间
参考七牛的API文档,基本能够涉及到的是
router.get('/qiniu', async (ctx, next) => { const bucket = 'activity' const accessKey = '2LCxxxrxxx' const secretKey = 'SXrdqdvxxx' const mac = new qiniu.auth.digest.Mac(accessKey, secretKey); const policyParams = { scope: bucket } const putPolicy = new qiniu.rs.PutPolicy(policyParams); const uploadToken = putPolicy.uploadToken(mac); ctx.body = uploadToken }) 复制代码
function base64ToBlob(dataurl) { var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1], bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n); while (n--) { u8arr[n] = bstr.charCodeAt(n); } return new Blob([u8arr], { type: mime }); } 复制代码
// 这个token 就是 server接口返回的token const token = '2LC7KTxxx' const config = { useCdnDomain: true, region: qiniu.region.z1 }; const putExtra = { fname: "", params: {}, mimeType: [] || null }; 复制代码
const inputTarget = document.querySelector('input') inputTarget.onchange = (data) => { const imgfile = inputTarget.files[0] const reader = new FileReader(); reader.readAsDataURL(imgfile); reader.onload = function (e) { const urlData = this.result; const blobData = base64ToBlob(urlData) // 这里第一个参数的形式是blob const observable = qiniu.upload(blobData, 'filename.png', token, putExtra, config) const observer = { next(res) {console.log(res)}, error(err) {console.log(err)}, complete(res) {console.log(res)} } // 注册observer 对象 observable.subscribe(observer) } } 复制代码
文件就能够被传到七牛了
能够看到这里返回的是一个hash和key,图片最后完整的访问路径,是你的七牛上配置的域名+key
在七牛建立一个新空间的话,会提供一个30天的免费域名可使用
原来是把
const config = { useCdnDomain: true, region: 'qiniu.region.z0' } 复制代码
这里的region 写错了,不该是字符串,就是一个七牛的变量
const config = { useCdnDomain: true, region: qiniu.region.z0 } 复制代码
这个参数是取决于你的空间存储区域选择的是哪里
对照文档 区域 进行z0 z1的选择
是由于第一次的时候,直接将 input的files[0] 值上传, 这里与文档要求的参数格式不一致 文档里对这个参数的要求是blob,因此记得这里须要转化一下文件格式
之前的demo写的一直失败就搁置了,今天从新跑了一次,再次吐槽七牛的文档,写的真是让人头大
在开发中,有使用一个webpack的配置, qiniu-webpack-plugin
参照这个的使用方式,另外写一个上传plugin
涉及到的一些文档
// 这个是编译文件编译到的文件夹 const filePath = path.resolve(__dirname, 'public') new QiuniuUploadPlugin({ bucket, accessKey, secretKey, domain, path: filePath }) 复制代码
这个的逻辑大部分和从后端直接上传到七牛有重合,这里只把另外一部分写出来
class QiuniuUploadPlugin { constructor () {...} uploadQn (filename) {...} apply (compiler) { const pluginName = 'QiuniuUploadPlugin' // 事件钩子 compiler.hooks.run.tap(pluginName, compilation => { console.log("webpack 构建过程开始!") }); // afterEmit - 生成资源到 output 目录以后将触发 异步钩子 - tapPromise compiler.hooks.afterEmit.tapPromise(pluginName, (compilation) => { let { assets } = compilation // assets 这里拿到的assets是一个对象 key是文件名 value是相关关参数 咱们只须要key // assets -->>> { 'index.js' : xxxx } // 遍历全部的文件名 进行七牛的上传 const allUplaod = Object.keys(assets).map((item) => { return this.uplaodQn(item) }) return Promise.all(allUplaod) }) } } 复制代码