Skip to content

1.1 创建基础的http服务

js
const http = require("http");
const url = require("url");

const config = {
  port: 3000,
};
http
  .createServer((req, res) => {
    var pathname = url.parse(req.url).pathname;
    console.log(pathname);
    res.writeHead(200, { "Content-Type": "text/plain" });
    res.write("Hello World");
    res.end();
  })
  .listen(config.port, () => {
    console.log(`正在监听=======> ${config.port}端口`);
  });

1.2 添加路由处理

js
const http = require("http");
const url = require("url");

const config = {
  port: 3000,
};

const router = {
  "/": (req, res) => {
    res.writeHead(200, { "Content-Type": "text/plain" });
    res.write("Hello World");
    res.end();
  },
  "/downloads": (req, res) => {
    res.writeHead(200, { "Content-Type": "text/plain" });
    res.write("download");
    res.end();
  },
  "/upload": (req, res) => {
    res.writeHead(200, { "Content-Type": "text/plain" });
    res.write("upload");
    res.end();
  },
};

const route = (pathname, req, res) => {
  if (router[pathname]) {
    router[pathname](req, res);
  } else {
    res.writeHead(404, { "Content-Type": "text/plain" });
    res.write(`404 not found =========> ${pathname}`);
    res.end();
  }
};

http
  .createServer((req, res) => {
    var pathname = url.parse(req.url).pathname;
    route(pathname, req, res);
    console.log(pathname);
  })
  .listen(config.port, () => {
    console.log(`正在监听=======> ${config.port}端口`);
  });

1.3 读取文件夹,将文件夹中的信息返回

js
"/downloads": (req, res) => {
    //文件列表页面
    const dirPath = path.join(__dirname, "./uploads");
    let result = "";
    if (!fs.existsSync(dirPath)) {
      fs.mkdirSync(dirPath);
    }
    fileList = fs.readdirSync(dirPath);
    let html = "";
    fileList.forEach((fileName, index) => {
      html += `<div><a target="_blank" href="/download?fileName=${fileName}" download="${fileName}">${
        index + 1
      }: ${fileName}</a></div>`;
    });
    res.end(html);
  },

1.4 实现点击文件名称,下载文件

js
"/download": (req, res) => {
    const { query } = url.parse(req.url);
    const fileName = query.slice(9);
    const filePath = path.join(__dirname, `./uploads/${fileName}`);
    console.log(filePath);
    const stat = fs.statSync(filePath);
    if (!stat.isFile()) return res.end("文件不存在");
    // 读取
    const readStream = fs.createReadStream(filePath);
    // const writeStream = fs.createWriteStream(fileName)
    res.writeHead(200, {
      "Content-Type": "application/octet-stream",
    });
    readStream.pipe(res);
  },

1.5 文件上传页面

js
"/upload": (req, res) => {
    const html = `<html>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <form action="/uploadFile" method="POST" enctype="multipart/form-data">
        <span>选择文件</span>: <input type="file" name="file"/>
        <br>
        <input type="submit">
    </form>
    </html>
    `
    res.end(html);
  },

1.6 文件上传方法

js
/*
由于使用的是`multipart/form-data`类型, 获取到的文件数据需要解析, 这里用到一个npm包 `busboy`
`npm init -y ` 初始化项目
`npm install -S  busboy` 安装包

导入 `const Busboy = require('busboy')`
*/

"/uploadFile": (req, res) => {
    const bb = Busboy({ headers: req.headers });
    bb.on('file', (name, file, info) => {
        // 名字 大小 格式
        const { filename } = info;
        // 根据时间创建名字 - 防止重名
        const filePath = path.join(__dirname, `./uploads/${Date.now()}__${filename}`);
        // 写入流
        file.pipe(fs.createWriteStream(filePath));
    });
    bb.on('finish', function () {
        res.writeHead(301, { Location: "/downloads" });
        res.end();
    })
    req.pipe(bb)
  },

1.7 最终代码

js
const http = require("http");
const url = require("url");
const fs = require("fs");
const path = require("path");

const Busboy = require("busboy");

const config = {
  port: 3000,
};

const router = {
  "/": (req, res) => {
    const html = `
    <html>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <body>
            <a href="/downloads">文件列表</a>
            <br>
            <a href="/upload">文件上传</a>
        </body>
    </html>
    `;
    res.end(html);
  },
  "/downloads": (req, res) => {
    //文件列表页面
    const dirPath = path.join(__dirname, "./uploads");
    if (!fs.existsSync(dirPath)) {
      fs.mkdirSync(dirPath);
    }
    fileList = fs.readdirSync(dirPath);
    let str = "";
    fileList.forEach((fileName, index) => {
      str += `<div>================> <a target="_blank" href="/download?fileName=${fileName}" download="${fileName}">
      ${fileName}</a></div>`;
    });
    const html = `
    <html>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        ${str}
    </html>
    `;
    res.end(html);
  },
  "/download": (req, res) => {
    const { query } = url.parse(req.url);
    if (!query) {
      res.writeHead(301, { Location: "/" });
      return res.end();
    }
    const fileName = query.slice(9);
    const filePath = path.join(__dirname, `./uploads/${fileName}`);
    console.log(filePath);
    const stat = fs.statSync(filePath);
    if (!stat.isFile()) return res.end("文件不存在");
    // 读取
    const readStream = fs.createReadStream(filePath);
    // const writeStream = fs.createWriteStream(fileName)
    res.writeHead(200, {
      "Content-Type": "application/octet-stream",
    });
    readStream.pipe(res);
  },
  "/upload": (req, res) => {
    const html = `<html>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <form action="/uploadFile" method="POST" enctype="multipart/form-data">
        <span>选择文件</span>: <input type="file" name="file"/>
        <br>
        <input type="submit">
    </form>
    </html>
    `;
    res.end(html);
  },
  "/uploadFile": (req, res) => {
    const bb = Busboy({ headers: req.headers });
    bb.on("file", (name, file, info) => {
      // 名字 大小 格式
      const { filename } = info;
      // 根据时间创建名字 - 防止重名
      const filePath = path.join(
        __dirname,
        `./uploads/${Date.now()}__${filename}`
      );
      // 写入流
      file.pipe(fs.createWriteStream(filePath));
    });
    bb.on("finish", function () {
      res.writeHead(301, { Location: "/downloads" });
      res.end();
    });
    req.pipe(bb);
  },
};

const route = (pathname, req, res) => {
  if (router[pathname]) {
    router[pathname](req, res);
  } else {
    res.writeHead(404, { "Content-Type": "text/plain" });
    res.write(`404 not found =========> ${pathname}`);
    res.end();
  }
};

http
  .createServer((req, res) => {
    var pathname = url.parse(req.url).pathname;
    route(pathname, req, res);
    console.log(pathname);
  })
  .listen(config.port, () => {
    console.log(`正在监听=======> ${config.port}端口`);
  });