Node.js如何将文件名和尺寸作为查询参数传递实现图片缩放
问题根因定位
你遇到的报错直接原因是:在路由回调里定义了resizeImage异步函数后,直接return res.send(resizeImage),把函数本身作为参数传给了res.send,而res.send仅接受字符串、Buffer、JSON等类型的内容,不接受函数类型,因此直接抛出类型错误。
除此之外你的代码还存在几个隐性问题:
fs.promises.access是异步方法,现有getAccessToFiles用同步try/catch捕获不到错误,返回的判断结果完全无效- 图片路径拼接没有加路径分隔符,会出现
xxx/imagesmyImage.jpg这类错误路径 - 定义了
exportImages指向uploads输出文件夹,但实际代码里把处理后的图片写到了原图片文件夹,不符合需求 - 没有从请求中提取查询参数,也没有做参数合法性校验
修复步骤
1. 修改utilities.ts文件
把文件存在性校验改为异步逻辑,适配异步fs方法:
import { promises as fs } from "fs"; // 改为异步函数,正确校验文件是否存在 let getAccessToFiles = async (path: string): Promise<boolean> => { try { await fs.access(path) return true; } catch (err) { return false; } } let getFilesName = ( imageToResize: string, width: number | null, height: number | null ): string => { let filename = imageToResize; if (width) { filename += `width${width}`; } if (height) { filename += `height${height}`; } return `${filename}.jpg` }; export { getAccessToFiles, getFilesName };
2. 修改路由逻辑文件
补充参数提取、参数校验、路径修复、函数调用逻辑:
import express, { Request, Response, Router } from "express"; import path from "path"; import sharp from "sharp"; import { promises as fs } from "fs"; import { getAccessToFiles, getFilesName } from "../../utils/utilities"; const resizeImages: Router = Router(); // 定义输入输出路径 const importImages = path.resolve(__dirname, "images"); const exportImages = path.resolve(__dirname, "uploads"); // 提前创建输出文件夹,避免写入报错 fs.mkdir(exportImages, { recursive: true }).catch(err => console.log('创建输出文件夹失败', err)); resizeImages.get("/", async (req: Request, res: Response) => { // 提取查询参数 const { filename, width, height } = req.query; // 参数合法性校验 if (!filename) { return res.status(400).json({ error: "缺少必填参数filename" }); } const parsedWidth = width ? Number(width) : null; const parsedHeight = height ? Number(height) : null; if (parsedWidth && isNaN(parsedWidth)) { return res.status(400).json({ error: "width必须为数字" }); } if (parsedHeight && isNaN(parsedHeight)) { return res.status(400).json({ error: "height必须为数字" }); } // 校验原图是否存在 const originImagePath = path.join(importImages, `${filename}.jpg`); const isOriginExist = await getAccessToFiles(originImagePath); if (!isOriginExist) { return res.status(404).json({ error: "指定的原图不存在" }); } const resizeImage = async ( imageName: string, width: number | null, height: number | null ): Promise<string> => { const resizedImageName = getFilesName(imageName, width, height); const outputPath = path.join(exportImages, resizedImageName); // 已处理过的图片直接返回,避免重复处理 const isResizedExist = await getAccessToFiles(outputPath); if (isResizedExist) { return resizedImageName; } try { await sharp(originImagePath) .resize(width, height) .jpeg() .toFile(outputPath); } catch (err) { res.status(400).json({ error: err}); return '' } return resizedImageName; }; // 调用处理函数,拿到结果后再返回给前端 const resultName = await resizeImage(filename as string, parsedWidth, parsedHeight); if (resultName) { // 可选择返回文件名,或者直接返回图片文件 res.send(`图片处理完成,文件名:${resultName}`) // 若要直接返回图片:res.sendFile(path.join(exportImages, resultName)) } }); export default resizeImages;
其他注意事项
- 要确保
images文件夹和代码文件的相对路径正确,如果TS编译后目录结构有变化,可以改用process.cwd()拼接项目根目录下的路径 app.use(express.json())不需要写在路由文件中,放在项目入口的全局配置里即可
内容的提问来源于stack exchange,提问作者fyardlest
相关产品推荐
相关产品推荐

