如何在AWS Lambda函数中访问文件?本地正常Lambda报错ENOENT
Lambda函数中文件访问失败的解决方案
最近切换到Serverless架构后,Lambda函数无法访问文件,本地运行正常的代码部署后报错:
Error: ENOENT: no such file or directory, open 'tmp/file 1-1692962065917.pdf'
原代码及说明
用户上传PDF文件后,将其保存到本地tmp目录,根据用户选择调用处理函数完成操作,之后删除原文件。原代码如下:
const serverless = require("serverless-http"); const express = require("express"); const multer = require('multer'); const fs = require('fs'); const { PDFDocument } = require('pdf-lib'); const http = require('http'); const cors = require('cors'); const os = require('os'); const cluster = require('cluster'); const { default: e } = require('express'); const path = require('path'); // count total number of cpu const cpuNums = os.cpus().length; console.log("Total Number of Cpus(CORS):"+cpuNums); var date = new Date(); const app = express(); var check=0; app.use(cors({ origin: '*', })); var fname; // Set up multer to handle file uploads const storage = multer.diskStorage({ destination: (req, file, cb) => { cb(null, './tmp/'); }, filename: (req, file, cb) => { check++; fname = `${file.fieldname} ${check}-${Date.now()}.pdf`; console.log("Filename : "+fname); cb(null, fname); }, }); const upload = multer({ storage }); app.post('/', upload.single('file'), (req, res,next) => { console.log("================================================="); console.log("API Last Build Date " + date.toLocaleDateString()); console.log("API Last Build Time" + date.toLocaleTimeString()); console.log(date.getFullYear()+'-'+(date.getMonth()+1)+'-'+date.getDate()); console.log("==========================="); console.log("LAST API CALL TIME:--" + date.toLocaleString('en-US', { timeZone: 'Asia/Kolkata' })); console.log("==========================="); console.log("Your IP Addresss is: " + req.socket.localAddress); console.log("================================================="); // Read the input PDF file const file = req.file; if (!file) { const error = new Error("Please upload a file"); error.httpStatusCode = 400; return next(error); } // crop uploaded file async function cropPDF(inputPath, outputPath, x, y, width, height) { // Read the input PDF file let pdfDoc = await PDFDocument.load(fs.readFileSync(inputPath)); // Loop through all pages in the PDF for (let i = 0; i < pdfDoc.getPages().length; i++) { // Get the page that you want to crop let page = pdfDoc.getPage(i); // Set the crop box for the page page.setCropBox(x, y, width, height); } // Save the output PDF file fs.writeFileSync(outputPath, await pdfDoc.save()); fs.unlink( './tmp/'+fname, (err) => { if (err) { console.error(err); } else { console.log('File deleted successfully'); } }); res.download(outputPath); } if(req.body.Ecommerce==2) { cropPDF('./tmp/' + fname,'outputfiledownload.pdf', 170, 467, 255, 353) .then(() => { console.log("PDF is cropped"); }) .catch((error) => { console.log(error); }); } }); module.exports.handler = serverless(app);
问题原因及解决方案
Lambda临时目录路径错误
Lambda运行环境中,唯一可写的临时目录是/tmp/(绝对路径),而你使用的相对路径./tmp/会指向代码包内的只读目录,且该目录默认不存在,导致文件保存失败。关键代码修改
- 修改multer的存储目录为绝对路径:
const storage = multer.diskStorage({ destination: (req, file, cb) => { cb(null, '/tmp/'); // 改用绝对路径 }, // 其余代码不变 });- 调整所有文件路径为绝对路径:
async function cropPDF(inputPath, outputPath, x, y, width, height) { let pdfDoc = await PDFDocument.load(fs.readFileSync(inputPath)); for (let i = 0; i < pdfDoc.getPages().length; i++) { let page = pdfDoc.getPage(i); page.setCropBox(x, y, width, height); } // 输出文件也存到/tmp目录 const tempOutputPath = `/tmp/${outputPath}`; fs.writeFileSync(tempOutputPath, await pdfDoc.save()); // 删除原文件时用绝对路径 fs.unlink(`/tmp/${fname}`, (err) => { if (err) console.error(err); else console.log('File deleted successfully'); }); res.download(tempOutputPath); }- 调用cropPDF时传入正确路径:
cropPDF(`/tmp/${fname}`, 'outputfiledownload.pdf', 170, 467, 255, 353)移除无用代码
Lambda是单进程运行环境,cluster和os.cpus()相关代码无意义,建议删除以减少资源消耗。
内容的提问来源于stack exchange,提问作者Hasti Ghelani
相关产品推荐
相关产品推荐

