AWS Lambda(Node.js)转Office文件为PDF遇TypeError报错求助
问题描述
开发一款基于Lambda Layer中LibreOffice的AWS Lambda(Node.js)函数,用于将Office文件转换为PDF。调试时多次出现不同报错,当前遇到的错误:
"errorType": "TypeError", "errorMessage": "Cannot read properties of undefined (reading '0')"
报错位置在/var/task/index/index.js第36行,对应代码:body = event.Records[0].body;。尝试直接指定文件名(test.doc)但无效,使用的代码如下:
const https = require('https'); const path = require('path'); const fs = require('fs'); var async = require('async'); const {writeFileSync} = require('fs'); const lambdafs = require('lambdafs'); const {execSync} = require('child_process'); var AWS = require('aws-sdk'); const inputPath = path.join( '/opt', 'lo.tar.br'); const outputPath = '/tmp/'; const bucketName = 'doc-conversion-tests'; module.exports.handler = async (event, context) => { console.log(execSync('ls -alh /opt').toString('utf8')); try { // Decompressing let decompressed = { file: await lambdafs.inflate(inputPath) }; console.log('output brotli de:----', decompressed); } catch (error) { console.log('Error brotli de:----', error); } try { console.log(execSync('ls -alh /opt').toString('utf8')); } catch (e) { console.log(e); } var body = ""; //S3 put event body = event.Records[0].body; console.log('s3 bucket file name from event:', body); // get file from s3 bucket var s3fileName = body; var newFileName = Date.now()+'.pdf'; var s3 = new AWS.S3({apiVersion: '2006-03-01'}); var fileStream = fs.createWriteStream('/tmp/'+s3fileName); var getObject = function(keyFile) { return new Promise(function(success, reject) { s3.getObject( { Bucket: bucketName, Key: keyFile }, function (error, data) { if(error) { reject(error); } else { success(data); } } ); }); } let fileData = await getObject(s3fileName); try{ fs.writeFileSync('/tmp/'+s3fileName, fileData.Body); } catch(err) { // An error occurred console.error('file write:', err); } const convertCommand = `export HOME=/tmp && /tmp/lo/instdir/program/soffice.bin --headless --norestore --invisible --nodefault --nofirststartwizard --nolockcheck --nologo --convert-to "pdf:writer_pdf_Export" --outdir /tmp /tmp/${s3fileName}`; try { console.log(execSync(convertCommand).toString('utf8')); } catch (e) { console.log(execSync(convertCommand).toString('utf8')); } console.log(execSync('ls -alh /tmp').toString('utf8')); function uploadFile(buffer, fileName) { return new Promise((resolve, reject) => { s3.putObject({ Body: buffer, Key: fileName, Bucket: bucketName, }, (error) => { if (error) { reject(error); } else { resolve(fileName); } }); }); } let fileParts = s3fileName.substr(0, s3fileName.lastIndexOf(".")) + ".pdf"; let fileB64data = fs.readFileSync('/tmp/'+fileParts); await uploadFile(fileB64data, 'pdf/'+fileParts); console.log('new pdf converted and uploaded!!!'); };
错误原因
第36行报错是因为event.Records未定义,说明当前Lambda触发的事件不是S3 Put事件结构:
- 手动测试时用了默认测试事件,而非正确的S3事件模板;
- 通过其他方式触发Lambda,事件结构不符合S3上传格式;
- 直接指定文件名时,未注释掉依赖
event.Records的代码,导致代码仍尝试读取不存在的字段。
解决方案
1. 确保触发事件为正确的S3 Put结构
如果通过S3上传触发Lambda,确认S3触发器已正确配置;如果手动测试,使用AWS提供的S3 Put事件模板,示例结构如下:
{ "Records": [ { "body": "test.doc" } ] }
2. 添加事件校验,避免崩溃
在读取event.Records前增加判断,防止因事件格式错误导致函数崩溃:
var body = ""; // 校验事件结构 if (event.Records && event.Records.length > 0) { body = event.Records[0].body; console.log('s3 bucket file name from event:', body); } else { // 测试时手动指定文件名 body = "test.doc"; console.log('Using manual test filename:', body); } var s3fileName = body;
3. 手动测试时的正确方式
如果要跳过S3事件直接测试文件转换,直接给s3fileName赋值,并注释掉读取event.Records的代码:
// 注释掉原事件读取代码 // var body = ""; // body = event.Records[0].body; // console.log('s3 bucket file name from event:', body); // 手动指定文件名 var s3fileName = "test.doc";
4. 额外检查点
- 确认Lambda Layer中的
lo.tar.br已正确部署,解压路径/tmp/lo存在; - 检查S3桶
doc-conversion-tests中存在test.doc文件,且Lambda有该桶的读写权限; - 转换命令中的LibreOffice路径
/tmp/lo/instdir/program/soffice.bin是否正确,可通过ls -alh /tmp/lo/instdir/program确认文件存在。
内容的提问来源于stack exchange,提问作者Nitrox
相关产品推荐
相关产品推荐

