linwu-hi / code-interview

前端面试小册,包含Vue面试题,React面试题,JS面试题,HTTP面试题,工程化面试题,CSS面试题,算法面试题,大厂面试题,高频面试题
194 stars 23 forks source link

面试官:如何实现文件上传?说说你的思路 #160

Open linwu-hi opened 1 year ago

linwu-hi commented 1 year ago

面试官:如何实现文件上传?说说你的思路

一、什么是文件上传?

文件上传在日常开发中应用很广泛,比如在发微博、发微信朋友圈等操作中都会用到图片上传功能。由于浏览器的安全限制,浏览器不能直接操作文件系统,因此需要通过浏览器暴露出来的统一接口来访问文件,然后将文件内容读取到指定的内存中,并执行提交请求操作,将内存中的文件内容上传到服务端,服务端再解析前端传来的数据信息,最终将文件保存到服务器的文件系统中。

文件上传需要设置请求头为content-type: multipart/form-data,其中multipart表示互联网上的混合资源,即资源由多种元素组成,而form-data表示可以使用HTML Forms和POST方法上传文件。

文件上传的请求结构如下:

POST /upload HTTP/1.1
Host: example.com
Content-Type: multipart/form-data; boundary=--------------------------1234567890

--------------------------1234567890
Content-Disposition: form-data; name="file"; filename="example.jpg"
Content-Type: image/jpeg

... binary data of the image ...
--------------------------1234567890--

其中,boundary表示分隔符,用于分隔不同的表单项。每个表单项必须包含Content-Disposition头,其他头信息如Content-Type为可选项。

二、如何实现文件上传?

文件上传可以分为两个步骤:

  1. 文件的上传
  2. 文件的解析

1. 文件上传

在前端,我们可以通过HTML的<input type="file">元素来实现文件上传的表单:

<form action="http://localhost:8080/api/upload" method="post" enctype="multipart/form-data">
    <input type="file" name="file" id="file" value="" multiple="multiple" />
    <input type="submit" value="提交"/>
</form>

在后端,我们可以使用Koa框架中的koa-body中间件来解析上传的文件数据:

npm install koa-body
const Koa = require('koa');
const koaBody = require('koa-body');
const app = new Koa();

app.use(koaBody({
    multipart: true,
    formidable: {
        maxFileSize: 200 * 1024 * 1024    // 设置上传文件大小最大限制,默认2M
    }
}));

app.use(async (ctx) => {
    // 获取上传的文件
    const file = ctx.request.files.file;
    // 创建可读流
    const reader = fs.createReadStream(file.path);
    let filePath = path.join(__dirname, 'public/upload/') + `/${file.name}`;
    // 创建可写流
    const upStream = fs.createWriteStream(filePath);
    // 可读流通过管道写入可写流
    reader.pipe(upStream);
    ctx.body = "上传成功!";
});

app.listen(8080, () => {
    console.log('Server started on http://localhost:8080');
});

2. 文件解析

在服务器端,我们需要将上传的文件进行解析,保存到指定的目录中。在上述代码中,我们通过使用fs模块来处理文件的保存操作。

除了使用koa-body,我们还可以使用koa-multer中间件来实现文件上传:

npm install koa-multer
const Koa = require('koa');
const Router = require('koa-router');
const multer = require('koa-multer');
const path = require('path');

const app = new Koa();
const router = new Router();

const storage = multer.diskStorage({
  destination: (req, file, cb) => {
    cb(null, "./upload/")
  },
  filename: (req, file, cb) => {
    cb(null, Date.now() + path.extname(file.originalname))
  }
})

const upload = multer({
  storage
});

router.post("/upload", upload.single('file'), (ctx, next) => {
  console.log(ctx.req.file); // 获取上传文件
})

app.use(router.routes());

app.listen(8080, () => {
    console.log('Server started on http://localhost:8080');
});

以上代码中,我们使用multer中间件来实现文件上传,storage选项用于设置文件的保存路径和文件名,upload.single('file')表示只上传单个文件。

参考文献