Skip to content

❤Node14-文件上传接口

写完了图片上传接口以后,简单修改就可以作为我们的文件上传接口使用了,接下来我们完整看看需要哪些部分。

1、文件上传导入

javascript
import multer from 'multer'
import { fileURLToPath } from 'url';
import path,{ dirname, join } from 'path';

2、设置文件存储引擎

// 设置存储引擎

javascript
const storage = multer.diskStorage({
    destination: function (req, file, cb) {
        cb(null, 'uploads/');
    },
    filename: function (req, file, cb) {
        cb(null, file.fieldname + '-' + Date.now() + path.extname(file.originalname));
    }
});

3、配置静态文件目录

这里配置主要是配置Multer和设置静态文件路径

javascript
// 配置Multer
const upload = multer({ storage: storage });
// const upload = multer({dest: 'uploads/'}); // 上传

// 设置静态文件路径
// app.use(express.static('uploads'));
app.use('/uploads', express.static('uploads'));

4、定义文件上传接口

// 处理文件上传

javascript
// 处理文件上传
app.post('/api/upload', upload.single('file'), (req, res) => {
  // 获取上传的文件信息
  const file = req.file;
  if (!file) {
     return res.status(400).send('No file uploaded.');
  }else{
    res.json({
        code: '200',
        data: file,
        url:`http://localhost:${PORT}`+'/uploads/'+req.file.filename,
    });
  }
});

url进行拼接文件路径以及拼接的文件名称 (这里不知道为啥一直影响所以只能把这个放下面)

url:http://localhost:${PORT}+'/uploads/'+req.file.filename,

直接测试我们的接口地址http://localhost:8888/api/upload

返回数据如下:

javascript
{
    "fieldname": "file",
    "originalname": "123.xlsx",
    "encoding": "7bit",
    "mimetype": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
    "destination": "uploads/",
    "filename": "file-1714036800721.xlsx",
    "path": "uploads\\file-1714036800721.xlsx",
    "size": 9388
}

这里我们也可以略微精简一些

浏览器之中打开这个文件查看数据http://localhost:8888/uploads/file-1714036800721.xlsx

OK!返回数据毫无问题!

5、优化一下完善token

接下来加上我们的token认证接口,把之前的token认证接口放开,这个时候你就知道为什么一开始我去掉token了

这个时候我们拿node写图片和文件上传接口就遇到一个问题,如果我加了接口的token验证,然后我的图片上传以后本地的路径访问就需要token授权,这种情况如何解决呢?

我们返回的图片路径如图所示:

然而我们的图片却不显示

直接在浏览器访问

思考:
我们一开始将我们的uploads文件作为我们的静态文件目录,添加token认证以后,无法访问

那我们是不是可以排除掉所有包含uploads接口达到排除呢?

正则完善一下我们的expressjwt排除接口

plain
  expressJWT.expressjwt({ secret: secretKey, algorithms: ["HS256"] }).unless({
    // path: [/^\/api\//],
    path: [
            '/',
            '/api/login',
            '/api/register',
            '/api/resetPwd',
            '/api/user',
            '/api/upload',
            '/api/uploadImage',
            `/api/uploadImage:id`,
     ],
    // 排除所有包含uploads的路径
    custom: (req) => {
        return req.originalUrl.includes('/uploads');
    }
  })
);

这个时候我们的图片静态确实没问题了!

思考:
这样同样也会给我们上传接口带来不安全的因素,于是我们排除一下上传的接口以外的其他接口需要token(也就是排除排除除了接口'/api/uploadImage'和'/api/upload'以外其他里面携带'/uploads'字符串的请求)

是不是我们还可以用其他方式完善:

expressJWT.expressjwt({ secret: secretKey, algorithms: ["HS256"] }).unless({}) 这段代码的使用中如何排除所有接口里面携带'/uploads'字符串并且为get的请求?

javascript

expressJWT.expressjwt({ secret: secretKey, algorithms: ["HS256"] }).unless({ 
// 排除除了'/api/uploadImage'和'/api/upload'以外的其他路径且包含/uploads的请求 
custom: (req) => { return !['/api/uploadImage', '/api/upload'].includes(req.originalUrl) && req.originalUrl.includes('/uploads'); } })

再次验证,毫无问题

再优化一下,排除post以外的,因为请求路径其实是get

javascript
 custom: (req) => {
        return req.method !== 'POST' && req.originalUrl.includes('/uploads');
 }

再次验证,已生效!

6、优化文件存储位置

根据每天的日期在uploads创建文件夹进行存储,并将图片存储在日期下的img文件夹中,其他文件存储在日期下的file文件夹中,我们可以使用multer的diskStorage选项来定义自定义的文件存储设置。

有文件夹直接放,没文件夹则进行创建

最后我们的存储引擎就变成了这个样子3

设置存储引擎
获取当前日期
设置文件存储路径

javascript
设置存储引擎
const storage = multer.diskStorage({
    destination: (req, file, cb) => {
        // cb(null, 'uploads/');
        // 获取当前日期
        const date = new Date();
        const year = date.getFullYear();
        const month = (date.getMonth() + 1).toString().padStart(2, '0');
        const day = date.getDate().toString().padStart(2, '0');
        const dateString = `${year}-${month}-${day}`;

        // 设置文件存储路径
        let destination;
        if (file.mimetype.startsWith('image/')) {
            destination = `uploads/${dateString}/img`;
        } else {
            destination = `uploads/${dateString}/file`;
        }
         // 判断目录是否存在,不存在则创建
        fs.access(destination, (error) => {
            if (error) {
                fs.mkdirSync(destination, { recursive: true });
            }
            cb(null, destination);
        });
        
        // 创建文件夹
        // fs.mkdirSync(destination, { recursive: true });

        cb(null, destination);
    },
    filename: (req, file, cb) => {
        // 设置文件名为原始文件名
        cb(null, file.originalname);

        cb(null, file.fieldname + '-' + Date.now() + path.extname(file.originalname));
    }
});

完美收工!

Released under the MIT License.