koa 實現上傳文件

項目目錄:javascript

1.上傳單個文件html

思路:java

(1)獲取上傳文件,使用 const file = ctx.request.files.fileios

(2)咱們使用 fs.createReadStream 來讀取文件流;如代碼:const fileReader = fs.createReadStream(file.path); axios

(3)對當前上傳的文件保存到 /static/upload 目錄下,所以定義變量:const filePath = path.join(__dirname, '/static/upload/');數組

(4) 組裝文件的絕對路徑,代碼:const fileResource = filePath + `/${file.name}`;app

(5)使用 fs.createWriteStream 把該文件寫進去,如代碼:const writeStream = fs.createWriteStream(fileResource);koa

(6) 下面這段代碼就是判斷是否有該目錄,若是沒有改目錄,就建立一個 /static/upload 這個目錄,若是有就直接使用管道流pipe拼接文件,如代碼:fileReader.pipe(writeStream);post

if (!fs.existsSync(filePath)) {
  fs.mkdir(filePath, (err) => {
    if (err) {
      throw new Error(err);
    } else {
      fileReader.pipe(writeStream);
      ctx.body = {
        url: uploadUrl + `/${file.name}`,
        code: 0,
        message: '上傳成功'
      };
    }
  });
} else {
  fileReader.pipe(writeStream);
  ctx.body = {
    url: uploadUrl + `/${file.name}`,
    code: 0,
    message: '上傳成功'
  };
}

最後咱們使用 ctx.body 返回到頁面來,所以若是咱們上傳成功了,就會在upload頁面返回以下信息了;以下圖所示:ui

源碼:

static/upload.html

<!DOCTYPE html>
<html>
<head>
  <meta charset=utf-8>
  <title>文件上傳</title>
  <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
  <!-- 使用form表單提交
  <form action="http://localhost:3001/upload" method="post" enctype="multipart/form-data">
    <div>
      <input type="file" name="file">
    </div>
    <div>
      <input type="submit" value="提交"/>
    </div>
  </form>
  -->
  <div>
    <input type="file" name="file" id="file">
  </div>
  <script type="text/javascript">
    var file = document.getElementById('file');
    const instance = axios.create({
      withCredentials: true
    });
    file.onchange = function(e) {
      var f1 = e.target.files[0];
      var fdata = new FormData();
      fdata.append('file', f1);
      instance.post('http://localhost:3001/upload', fdata).then(res => {
        console.log(res);
      }).catch(err => {
        console.log(err);
      });
    }
  </script>
</body>
</html>

app.js

// 引入模塊
const Koa = require('koa');
const fs = require('fs');
const path = require('path');
const router = require('koa-router')();
const koaBody = require('koa-body');
const static = require('koa-static');

// 實例化
const app = new Koa();

app.use(koaBody({
  multipart: true, // 支持文件上傳
  formidable: {
    maxFieldsSize: 2 * 1024 * 1024, // 最大文件爲2兆
    multipart: true // 是否支持 multipart-formdate 的表單
  }
}));

const uploadUrl = "http://localhost:3001/static/upload";

// 配置路由
router.get('/', (ctx) => {
  // 設置頭類型, 若是不設置,會直接下載該頁面
  ctx.type = 'html';
  // 讀取文件
  const pathUrl = path.join(__dirname, '/static/upload.html');
  ctx.body = fs.createReadStream(pathUrl);
});

// 上傳文件
router.post('/upload', (ctx) => {
  // 獲取上傳文件
  const file = ctx.request.files.file;
  console.log(file);
  // 讀取文件流
  const fileReader = fs.createReadStream(file.path);
  console.log(fileReader);
  // 設置文件保存路徑
  const filePath = path.join(__dirname, '/static/upload/');
  // 組裝成絕對路徑
  const fileResource = filePath + `/${file.name}`;

  /**
   * 使用 createWriteStream 寫入數據,而後使用管道流pipe拼接
   */
  const writeStream = fs.createWriteStream(fileResource);
  // 判斷 /static/upload 文件夾是否存在,若是不在的話就建立一個
  if (!fs.existsSync(filePath)) {
    fs.mkdir(filePath, (err) => {
      if (err) {
        throw new Error(err);
      } else {
        fileReader.pipe(writeStream);
        ctx.body = {
          url: uploadUrl + `/${file.name}`,
          code: 0,
          message: '上傳成功'
        };
      }
    });
  } else {
    fileReader.pipe(writeStream);
    ctx.body = {
      url: uploadUrl + `/${file.name}`,
      code: 0,
      message: '上傳成功'
    };
  }
});

// 配置靜態資源路徑
app.use(static(path.join(__dirname)));

// 啓動路由
app.use(router.routes()).use(router.allowedMethods());

// 監聽端口號
app.listen(3001, () => {
  console.log('server is listen in 3001');
});

2.上傳多個文件

爲了支持多個文件上傳,和單個文件上傳,咱們須要把代碼改下,改爲以下:

static/upload.html

<!DOCTYPE html>
<html>

<head>
  <meta charset=utf-8>
  <title>文件上傳</title>
  <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>

<body>
  <!-- 使用form表單提交
  <form action="http://localhost:3001/upload" method="post" enctype="multipart/form-data">
    <div>
      <input type="file" name="file">
    </div>
    <div>
      <input type="submit" value="提交"/>
    </div>
  </form>
  -->
  <!--  上傳單個文件
  <div>
    <input type="file" name="file" id="file">
  </div>
  <script type="text/javascript">
    var file = document.getElementById('file');
    const instance = axios.create({
      withCredentials: true
    });
    file.onchange = function(e) {
      var f1 = e.target.files[0];
      var fdata = new FormData();
      fdata.append('file', f1);
      instance.post('http://localhost:3001/upload', fdata).then(res => {
        console.log(res);
      }).catch(err => {
        console.log(err);
      });
    }
  </script>
  -->
  <div>
    <input type="file" name="file" id="file" multiple="multiple">
  </div>
  <script type="text/javascript">
    var file = document.getElementById('file');
    const instance = axios.create({
      withCredentials: true
    });
    file.onchange = function (e) {
      var files = e.target.files;
      var fdata = new FormData();
      if (files.length > 0) {
        for (let i = 0; i < files.length; i++) {
          const f1 = files[i];
          fdata.append('file', f1);
        }
      }
      instance.post('http://localhost:3001/upload', fdata).then(res => {
        console.log(res);
      }).catch(err => {
        console.log(err);
      });
    }
  </script>
</body>

</html>

如上是多個文件上傳的html代碼和js代碼,就是把多個數據使用formdata一次性傳遞多個數據過去,如今咱們須要把app.js 代碼改爲以下了,app.js 代碼改的有點多,最主要是要判斷 傳過來的文件是單個的仍是多個的邏輯,全部代碼以下:

// 引入模塊
const Koa = require('koa');
const fs = require('fs');
const path = require('path');
const router = require('koa-router')();
const koaBody = require('koa-body');
const static = require('koa-static');

// 實例化
const app = new Koa();

app.use(koaBody({
  multipart: true, // 支持文件上傳
  formidable: {
    maxFieldsSize: 2 * 1024 * 1024, // 最大文件爲2兆
    multipart: true // 是否支持 multipart-formdate 的表單
  }
}));

const uploadUrl = "http://localhost:3001/static/upload";

router.get('/', (ctx) => {
  // 設置頭類型, 若是不設置,會直接下載該頁面
  ctx.type = 'html';
  // 讀取文件
  const pathUrl = path.join(__dirname, '/static/upload.html');
  ctx.body = fs.createReadStream(pathUrl);
});

/**
 * flag: 是不是多個文件上傳
 */
const uploadFilePublic = function (ctx, files, flag) {
  const filePath = path.join(__dirname, '/static/upload/');
  let file,
    fileReader,
    fileResource,
    writeStream;

  const fileFunc = function (file) {
    // 讀取文件流
    fileReader = fs.createReadStream(file.path);
    // 組裝成絕對路徑
    fileResource = filePath + `/${file.name}`;
    /*
     使用 createWriteStream 寫入數據,而後使用管道流pipe拼接
    */
    writeStream = fs.createWriteStream(fileResource);
    fileReader.pipe(writeStream);
  };
  const returnFunc = function (flag) {
    console.log(flag);
    console.log(files);
    if (flag) {
      let url = '';
      for (let i = 0; i < files.length; i++) {
        url += uploadUrl + `/${files[i].name},`
      }
      url = url.replace(/,$/gi, "");
      ctx.body = {
        url: url,
        code: 0,
        message: '上傳成功'
      };
    } else {
      ctx.body = {
        url: uploadUrl + `/${files.name}`,
        code: 0,
        message: '上傳成功'
      };
    }
  };
  if (flag) {
    // 多個文件上傳
    for (let i = 0; i < files.length; i++) {
      const f1 = files[i];
      fileFunc(f1);
    }
  } else {
    fileFunc(files);
  }

  // 判斷 /static/upload 文件夾是否存在,若是不在的話就建立一個
  if (!fs.existsSync(filePath)) {
    fs.mkdir(filePath, (err) => {
      if (err) {
        throw new Error(err);
      } else {
        returnFunc(flag);
      }
    });
  } else {
    returnFunc(flag);
  }
}

// 上傳單個或多個文件
router.post('/upload', (ctx) => {
  let files = ctx.request.files.file;
  const fileArrs = [];
  if (files.length === undefined) {
    // 上傳單個文件,它不是數組,只是單個的對象
    uploadFilePublic(ctx, files, false);
  } else {
    uploadFilePublic(ctx, files, true);
  }
});

// 配置靜態資源路徑
app.use(static(path.join(__dirname)));

// 啓動路由
app.use(router.routes()).use(router.allowedMethods());

// 監聽端口號
app.listen(3001, () => {
  console.log('server is listen in 3001');
});

而後我如今來演示下,當我選擇多個文件,好比如今選擇兩個文件,會返回以下數據:

當我如今只選擇一個文件的時候,只會返回一個文件,以下圖所示:

如上app.js改爲以後的代碼如今支持單個或多個文件上傳了。

轉自:https://www.cnblogs.com/tugenhua0707/p/10828869.html

.

相關文章
相關標籤/搜索