Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
linwu-hi opened this issue Jul 30, 2023 · 0 comments
Open

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

linwu-hi opened this issue Jul 30, 2023 · 0 comments
Labels

Comments

@linwu-hi
Copy link
Owner

linwu-hi commented Jul 30, 2023

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

一、什么是文件上传?

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

文件上传需要设置请求头为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')表示只上传单个文件。

参考文献

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant