MST
星途 面试题库

面试题:Node.js文件上传与下载场景下如何优化性能与安全性

在Node.js的文件上传与下载业务场景中,从性能优化和安全性加固两方面进行分析。性能优化方面,例如如何减少内存占用、提升I/O效率;安全性方面,如防止文件上传漏洞(如文件类型伪造、路径穿越等)和下载过程中的数据泄露。请详细阐述优化与加固的策略,并结合实际代码示例说明。
36.9万 热度难度
前端开发Node.js

知识考点

AI 面试

面试题答案

一键面试

性能优化策略

  1. 减少内存占用
    • 流式处理:在文件上传时,使用流(stream)而不是一次性读取整个文件到内存。Node.js 提供了 fs.createReadStreamfs.createWriteStream 来实现流式读写。
    • 示例代码
const express = require('express');
const app = express();
const multer = require('multer');
const storage = multer.memoryStorage();
const upload = multer({ storage: storage });

app.post('/upload', upload.single('file'), (req, res) => {
    const readStream = require('fs').createReadStream(req.file.path);
    const writeStream = require('fs').createWriteStream('uploads/' + req.file.originalname);
    readStream.pipe(writeStream);
    readStream.on('error', (err) => {
        console.error(err);
        res.status(500).send('Error uploading file');
    });
    writeStream.on('finish', () => {
        res.send('File uploaded successfully');
    });
});

const port = 3000;
app.listen(port, () => {
    console.log(`Server running on port ${port}`);
});
  • 解释:这里使用 multer 中间件接收文件,然后通过 createReadStreamcreateWriteStream 以流的方式将文件从临时位置移动到目标位置,避免了将整个文件加载到内存中。
  1. 提升I/O效率
    • 使用缓存:对于频繁下载的文件,可以考虑使用缓存。例如,使用 node - cache - manager 库。
    • 示例代码
const express = require('express');
const app = express();
const CacheManager = require('cache - manager');
const cache = CacheManager.caching({
    store: 'memory',
    max: 100,
    ttl: 60 * 1000 // 1 minute
});

app.get('/download/:filename', async (req, res) => {
    const cachedFile = await cache.get(req.params.filename);
    if (cachedFile) {
        res.set('Content - Type', 'application/octet - stream');
        res.send(cachedFile);
    } else {
        const file = require('fs').readFileSync('downloads/' + req.params.filename);
        cache.set(req.params.filename, file);
        res.set('Content - Type', 'application/octet - stream');
        res.send(file);
    }
});

const port = 3000;
app.listen(port, () => {
    console.log(`Server running on port ${port}`);
});
  • 解释:代码中使用 cache - manager 库实现了内存缓存。如果文件在缓存中,则直接从缓存中返回,减少了磁盘 I/O 操作。

安全性加固策略

  1. 防止文件上传漏洞
    • 文件类型验证:使用 file - type 库来验证文件的真实类型,防止文件类型伪造。
    • 示例代码
const express = require('express');
const app = express();
const multer = require('multer');
const fileType = require('file - type');
const storage = multer.memoryStorage();
const upload = multer({ storage: storage });

app.post('/upload', upload.single('file'), async (req, res) => {
    const type = await fileType.fromBuffer(req.file.buffer);
    if (!type ||!['image/png', 'image/jpeg'].includes(type.mime)) {
        return res.status(400).send('Only PNG and JPEG files are allowed');
    }
    const writeStream = require('fs').createWriteStream('uploads/' + req.file.originalname);
    writeStream.write(req.file.buffer);
    writeStream.end();
    writeStream.on('finish', () => {
        res.send('File uploaded successfully');
    });
});

const port = 3000;
app.listen(port, () => {
    console.log(`Server running on port ${port}`);
});
  • 解释:file - type 库通过分析文件头来确定文件的真实类型,这里只允许 PNG 和 JPEG 文件上传。
  • 路径穿越防范:对上传文件的路径进行严格检查和过滤,避免恶意用户通过路径穿越访问系统文件。
  • 示例代码
const express = require('express');
const app = express();
const multer = require('multer');
const storage = multer.memoryStorage();
const upload = multer({ storage: storage });

app.post('/upload', upload.single('file'), (req, res) => {
    const sanitizedFileName = req.file.originalname.replace(/[^\w\s.-]/g, '');
    if (sanitizedFileName.includes('..')) {
        return res.status(400).send('Invalid file name');
    }
    const writeStream = require('fs').createWriteStream('uploads/' + sanitizedFileName);
    writeStream.write(req.file.buffer);
    writeStream.end();
    writeStream.on('finish', () => {
        res.send('File uploaded successfully');
    });
});

const port = 3000;
app.listen(port, () => {
    console.log(`Server running on port ${port}`);
});
  • 解释:代码中通过正则表达式去除文件名中的非法字符,并检查文件名中是否包含 .. 来防止路径穿越。
  1. 防止下载过程中的数据泄露
    • 访问控制:确保只有授权用户可以下载文件。例如,结合身份验证中间件(如 express - jwt 用于 JWT 验证)。
    • 示例代码
const express = require('express');
const jwt = require('jsonwebtoken');
const app = express();
const secret = 'your - secret - key';

// 模拟用户登录
app.post('/login', (req, res) => {
    const user = { id: 1 };
    const token = jwt.sign(user, secret);
    res.send({ token });
});

// 下载文件路由,需要 JWT 验证
app.get('/download/:filename', (req, res, next) => {
    const token = req.headers['authorization'];
    if (!token) {
        return res.status(401).send('Access denied. No token provided.');
    }
    try {
        const decoded = jwt.verify(token.replace('Bearer ', ''), secret);
        req.user = decoded;
        next();
    } catch (err) {
        return res.status(400).send('Invalid token');
    }
}, (req, res) => {
    const file = require('fs').readFileSync('downloads/' + req.params.filename);
    res.set('Content - Type', 'application/octet - stream');
    res.send(file);
});

const port = 3000;
app.listen(port, () => {
    console.log(`Server running on port ${port}`);
});
  • 解释:这里使用 express - jwt 进行 JWT 验证,只有携带有效 JWT 的用户才能下载文件,防止数据泄露给未授权用户。