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

    .

  • 相关阅读:
    Object C学习笔记25-文件管理(一)
    实施项目--为什么开发人员一直在抱怨需求变动
    Git.Framework 框架随手记--准备工作
    一网打尽!2018网络安全事件最全的盘点
    林纳斯·托瓦兹和Linux行为准则:揭穿7个谬论
    LinkedList源码解析
    四种List实现类的对比总结
    HashMap源码解析
    volatile
    Java内存模型与共享变量可见性
  • 原文地址:https://www.cnblogs.com/crazycode2/p/11108356.html
Copyright © 2011-2022 走看看