服務端將圖片源傳遞到七牛,這種方式的流程是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) }) } } 複製代碼