zoukankan      html  css  js  c++  java
  • koa 实现上传文件

    项目目录:

    1.上传单个文件

    思路:

    (1)获取上传文件,使用 const file = ctx.request.files.file

    (2)我们使用 fs.createReadStream 来读取文件流;如代码:const fileReader = fs.createReadStream(file.path); 

    (3)对当前上传的文件保存到 /static/upload 目录下,因此定义变量:const filePath = path.join(__dirname, '/static/upload/');

    (4) 组装文件的绝对路径,代码:const fileResource = filePath + `/${file.name}`;

    (5)使用 fs.createWriteStream 把该文件写进去,如代码:const writeStream = fs.createWriteStream(fileResource);

    (6) 下面这段代码就是判断是否有该目录,如果没有改目录,就创建一个 /static/upload 这个目录,如果有就直接使用管道流pipe拼接文件,如代码:fileReader.pipe(writeStream);

    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页面返回如下信息了;如下图所示:

    源码:

    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

    .

  • 相关阅读:
    PAT (Basic Level) Practise 1013 数素数
    PAT (Basic Level) Practise 1014 福尔摩斯的约会
    codeforces 814B.An express train to reveries 解题报告
    KMP算法
    rsync工具
    codeforces 777C.Alyona and Spreadsheet 解题报告
    codeforces 798C.Mike and gcd problem 解题报告
    nginx + tomcat多实例
    MongoDB副本集
    指针的艺术(转载)
  • 原文地址:https://www.cnblogs.com/crazycode2/p/11108356.html
Copyright © 2011-2022 走看看