上傳文件到七牛空間

服務端進行上傳

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

server 接口部分

  • 基本參數
const bucket = 'cancan'
const accessKey = '2LC7KPjwnYdxxxc'
const secretKey = 'SXrxxx'
const domain = 'http://pq3xxxdn.com'
複製代碼
  • 獲取token
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
}
複製代碼
  • 拿到文件path以後進行七牛上傳
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
})
複製代碼

遇到的問題

  • post 接口 始終沒法解析到file參數

後來發現是由於 中間件只使用了 koa-bodyparser, 通常圖片上傳使用的是 koa-multer,可使用 koa-body來代替這兩個java

參考文章node

  • 臨時文件佔用大量磁盤空間

能夠看到,在將文件上傳到服務器的時候,會建立一個臨時文件- 接口中解析的那個 pathwebpack

path

對於服務器,能夠寫一個定時的腳本去清除這些文件。或者咱們在腳本增長一段邏輯,在成功上傳到七牛以後,手動將臨時文件進行刪除git

fs.unlink(path, (err) => {
  if (err) throw err;
  console.log('文件已刪除', path);
})
複製代碼

前端直接上傳

項目中的例子涉及到的圖片上傳,都是將文件上傳到服務器而後再去傳到七牛空間,這種操做方式,至關於在本身的服務器作了一層中轉站。開發者能夠在中轉站對圖片作一些處理而後在傳到七牛空間。可是有一些缺點github

  • 內存佔用量增大web

  • 臨時文件佔用磁盤空間,須要每次上傳以後須要進行文件刪除npm

若是開發中不須要中轉站,能夠考慮直接從前端將圖片上傳到七牛空間

參考七牛的API文檔,基本能夠涉及到的是

獲取上傳憑證 token

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
})
複製代碼

前端上傳代碼

  • base64轉 blob
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)
    }
    
}
複製代碼

result

文件就能夠被傳到七牛了

能夠看到這裏返回的是一個hash和key,圖片最後完整的訪問路徑,是你的七牛上配置的域名+key

在七牛建立一個新空間的話,會提供一個30天的免費域名可使用

遇到的問題

  • cdnUphost 解析失敗

原來是把

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 上傳七牛的插件

在開發中,有使用一個webpack的配置, qiniu-webpack-plugin

參照這個的使用方式,另外寫一個上傳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)

    })
  }
}

複製代碼
相關文章
相關標籤/搜索