Node.js 使用PDFKit在S3中动态存储PDF

Node.js 使用PDFKit在S3中动态存储PDF,node.js,pdf,amazon-s3,parse-server,node-pdfkit,Node.js,Pdf,Amazon S3,Parse Server,Node Pdfkit,我正在尝试创建一些图像的pdf(datauri格式)是nodejs,并将pdf存储在我的S3中。函数的返回将提供文件的S3URL 我在这里为服务器和节点画布使用parse server来创建图像的画布,然后使用PDFKit从画布元素创建pdf。(jsPdf不起作用)。现在,我希望使用AWS-SDK将此pdf发送到我的s3,并最终返回文件的URL。下面是我的代码,它一直工作到画布生成。我不知道pdf是否在第一时间创建,甚至在发送到s3之前。哦!整个事情都在heroku身上进行 Parse.Clou

我正在尝试创建一些图像的pdf(datauri格式)是nodejs,并将pdf存储在我的S3中。函数的返回将提供文件的S3URL

我在这里为服务器和节点画布使用parse server来创建图像的画布,然后使用PDFKit从画布元素创建pdf。(jsPdf不起作用)。现在,我希望使用AWS-SDK将此pdf发送到我的s3,并最终返回文件的URL。下面是我的代码,它一直工作到画布生成。我不知道pdf是否在第一时间创建,甚至在发送到s3之前。哦!整个事情都在heroku身上进行

Parse.Cloud.define('getBulkMeta',async (req)=>{
    const PDFDocument = require('pdfkit'),
        {Canvas,loadImage} = require('canvas');

        try {       
            let baseImg = await loadImage('data:image/png;base64,'+req.params.labels[0]);
            let labels = req.params.labels,
                allCanvas = [],
                rowH = baseImg.naturalHeight,
                rowW = baseImg.naturalWidth,
                perpage = req.params.size[1],
                pages = Math.ceil(labels.length/perpage),
                imgInd = 0,
                g = 10;
                size = req.params.size[0];

            for(var p=0;p<pages;p++){
                let canvas = new Canvas(rowW*((size=='A4')?2:1),rowH*((size=='A4')?2:1)),
                    ctx = canvas.getContext("2d");

                ctx.beginPath();
                ctx.rect(0,0,canvas.width,canvas.height)
                ctx.fillStyle = "#fff";
                ctx.fill();

                if(perpage == 1){
                    let img = await loadImage('data:image/png;base64,'+labels[imgInd++]);
                    ctx.drawImage(img,g,g,rowW-(2*g),rowH-(2*g));
                } else {
                    var thisImgInd = 0;
                    for (var r=0;r<2;r++){
                        for(var c=0;c<2;c++){
                            let img = await loadImage('data:image/png;base64,'+labels[imgInd++]);
                            ctx.drawImage(img,g+(c*(rowW-g/2)),g+(r*(rowH-g/2)),rowW-(1.5*g),rowH-(1.5*g));
                            thisImgInd++
                            if(thisImgInd>=perpage||imgInd>=labels.length){break;}
                        }
                        if(thisImgInd>=perpage||imgInd>=labels.length){break;}
                    }
                }
                allCanvas.push(canvas)
            }
        var thisPDF = new PDFDocument({layout: 'landscape',size:size});
        var bcoded;
        thisPDF.pipe(()=>{bcoded = new Buffer.from(thisPDF).toString('base64')});
        allCanvas.forEach((c,i)=>{
            if(i){thisPDF.addPage();}
            thisPDF.image(c.toDataURL(),0,0,thisPDF.page.width,thisPDF.page.width);
        })
        thisPDF.end();
        const S3_BUCKET = process.env.S3_BUCKET;
        aws.config.region = process.env.AWS_REGION;
        aws.config.signatureVersion  = 'v4';

        let s3 = new aws.S3();
        let fileName = req.params.name;
        let s3Params = {
            Bucket: S3_BUCKET,
            Body: bcoded,
            Key: fileName,
            ContentType : 'application/pdf',
            ACL: 'public-read'
        };
        s3.putObject(s3Params, (err, data) => {
            if(err){
                console.log('\n\n\n\n\n\n\n'+err+'\n\n\n\n\n\n\n');
                throw 'Error: '+ (err);
            }
            let returnData = {
                signedRequest: data,
                url: `https://${S3_BUCKET}.s3.amazonaws.com/${fileName}`
            };
            return (returnData);
        })
    } catch (e) {throw e;}
})
Parse.Cloud.define('getBulkMeta',异步(req)=>{
const PDFDocument=require('pdfkit'),
{Canvas,loadImage}=require('Canvas');
试试{
让baseImg=wait-loadImage('data:image/png;base64'+req.params.labels[0]);
让标签=请求参数标签,
allCanvas=[],
rowH=基本自然高度,
rowW=基本的自然宽度,
perpage=所需参数大小[1],
pages=Math.ceil(标签.长度/每页),
imgInd=0,
g=10;
大小=所需参数大小[0];
对于(var p=0;p=perpage | | imgInd>=labels.length){break;}
}
}
allCanvas.push(画布)
}
var thisPDF=新的PDFDocument({layout:'scape',size:size});
变异码;
thisPDF.pipe(()=>{bcoded=newbuffer.from(thisPDF.toString('base64')});
allCanvas.forEach((c,i)=>{
如果(i){thisPDF.addPage();}
thisPDF.image(c.toDataURL(),0,0,thisPDF.page.width,thisPDF.page.width);
})
thisPDF.end();
const S3_BUCKET=process.env.S3_BUCKET;
aws.config.region=process.env.aws_region;
aws.config.signatureVersion='v4';
设s3=new aws.s3();
让fileName=req.params.name;
设s3Params={
桶:S3_桶,
正文:b代码,
关键字:文件名,
ContentType:'application/pdf',
ACL:“公共读取”
};
s3.putObject(s3Params,(错误,数据)=>{
如果(错误){
console.log('\n\n\n\n\n\n\n'+err+'\n\n\n\n\n\n');
抛出“错误:”+(错误);
}
让返回数据={
signedRequest:数据,
url:`https://${S3_BUCKET}.S3.amazonaws.com/${fileName}`
};
返回(返回数据);
})
}捕捉(e){抛出e;}
})
更新。我用下面的代码将pdf文件保存在s3中:

    Parse.Cloud.define('getBulkMeta',async (req)=>{
    const PDFDocument = require('pdfkit'),
        {Canvas,loadImage} = require('canvas');

        try {       
            let baseImg = await loadImage('data:image/png;base64,'+req.params.labels[0]);
            let labels = req.params.labels,
                allCanvas = [],
                rowH = baseImg.naturalHeight,
                rowW = baseImg.naturalWidth,
                perpage = req.params.size[1],
                pages = Math.ceil(labels.length/perpage),
                imgInd = 0,
                g = 10;
                size = req.params.size[0];

            for(var p=0;p<pages;p++){
                let canvas = new Canvas(),
                    ctx = canvas.getContext("2d");

                canvas.height = rowH*((size=='A4')?2:1);
                canvas.width = rowW*((size=='A4')?2:1);

                ctx.beginPath();
                ctx.rect(0,0,canvas.width,canvas.height)
                ctx.fillStyle = "#fff";
                ctx.fill();

                if(perpage == 1){
                    let img = await loadImage('data:image/png;base64,'+labels[imgInd++]);
                    ctx.drawImage(img,g,g,rowW-(2*g),rowH-(2*g));
                } else {
                    var thisImgInd = 0;
                    for (var r=0;r<2;r++){
                        for(var c=0;c<2;c++){
                            let img = await loadImage('data:image/png;base64,'+labels[imgInd++]);
                            ctx.drawImage(img,g+(c*(rowW-g/2)),g+(r*(rowH-g/2)),rowW-(1.5*g),rowH-(1.5*g));
                            thisImgInd++
                            if(thisImgInd>=perpage||imgInd>=labels.length){break;}
                        }
                        if(thisImgInd>=perpage||imgInd>=labels.length){break;}
                    }
                }
                allCanvas.push(canvas)
            }
        var thisPDF = new PDFDocument({layout: 'landscape',size:size});
        let buffers = [],pdfData,returnData='Hi';
        thisPDF.on('data', buffers.push.bind(buffers));
        thisPDF.on('end',() => {
            pdfData = Buffer.concat(buffers);
            const S3_BUCKET = process.env.S3_BUCKET;
            aws.config.region = process.env.AWS_REGION;
            aws.config.signatureVersion  = 'v4';

            let s3 = new aws.S3();
            let fileName = req.params.name;
            let s3Params = {
                Bucket: S3_BUCKET,
                Body: pdfData,
                Key: (+new Date())+'-'+fileName,
                ContentType : 'application/pdf',
                ACL: 'public-read'
            };
            s3.putObject(s3Params,(err, data) => {
                delete pdfData,thisPDF;
                pdfData = null;thisPDF = null;
                if(err){ throw 'Error: '+ (err); }
                returnData = { signedRequest: data, url: `https://${S3_BUCKET}.s3.amazonaws.com/${fileName}` };
            })
        })
        allCanvas.forEach((c,i)=>{
            if(i){thisPDF.addPage();}
            thisPDF.image(c.toDataURL(),0,0,{fit:[thisPDF.page.width,thisPDF.page.height]});
        })
        thisPDF.end();
        return returnData;
    } catch (e) {throw e;}
})
Parse.Cloud.define('getBulkMeta',异步(req)=>{
const PDFDocument=require('pdfkit'),
{Canvas,loadImage}=require('Canvas');
试试{
让baseImg=wait-loadImage('data:image/png;base64'+req.params.labels[0]);
让标签=请求参数标签,
allCanvas=[],
rowH=基本自然高度,
rowW=基本的自然宽度,
perpage=所需参数大小[1],
pages=Math.ceil(标签.长度/每页),
imgInd=0,
g=10;
大小=所需参数大小[0];
对于(var p=0;p=perpage | | imgInd>=labels.length){break;}
}
}
allCanvas.push(画布)
}
var thisPDF=新的PDFDocument({layout:'scape',size:size});
让缓冲区=[],pdfData,returnData='Hi';
thisPDF.on('data',buffers.push.bind(buffers));
thisPDF.on('end',()=>{
pdfData=Buffer.concat(缓冲区);
const S3_BUCKET=process.env.S3_BUCKET;
aws.config.region=process.env.aws_region;
aws.config.signatureVersion='v4';
设s3=new aws.s3();
让fileName=req.params.name;
设s3Params={
桶:S3_桶,
正文:pdfData,
键:(+新日期())+'-'+文件名,
ContentType:'application/pdf',
ACL:“公共读取”
};
s3.putObject(s3Params,(错误,数据)=>{
删除pdfData,此PDF;
pdfData=null;thisPDF=null;
如果(错误){throw'错误:'+(错误);}
returnData={signedRequest:data,url:`https://${S3_BUCKET}.S3.amazonaws.com/${fileName}`};
})
})
allCanvas.forEach((c,i)=>{
如果(i){thisPDF.addPage();}
图像(c.toDataURL(),0,0,{fit:[thisPDF.page.width,thisPDF.page.height]});
})
thisPDF.end();
返回数据;
}捕捉(e){抛出e;}
})

但是,
returnData
总是给出“Hi”作为输出,而且函数似乎没有关闭-Heroku每次都抛出内存超出错误。

由于您使用异步函数创建PDF并将其发送到S3,因此您的云函数在这些操作实际完成之前返回。这就是为什么在
returnData
var中总是有
Hi
。您需要创建一个承诺,并等待该承诺在这两个操作结束时完成。应该是这样的:

await (new Promise((resolve, reject) => {
  var thisPDF = new PDFDocument({layout: 'landscape',size:size});
  let buffers = [];
  thisPDF.on('data', buffers.push.bind(buffers));
  thisPDF.on('end',() => {
    pdfData = Buffer.concat(buffers);
    const S3_BUCKET = process.env.S3_BUCKET;
    aws.config.region = process.env.AWS_REGION;
    aws.config.signatureVersion  = 'v4';

    let s3 = new aws.S3();
    let fileName = req.params.name;
    let s3Params = {
      Bucket: S3_BUCKET,
      Body: pdfData,
      Key: (+new Date())+'-'+fileName,
      ContentType : 'application/pdf',
      ACL: 'public-read'
    };
    s3.putObject(s3Params,(err, data) => {
      delete pdfData,thisPDF;
      pdfData = null;thisPDF = null;
      if(err){ reject(err); }
      returnData = { signedRequest: data, url: `https://${S3_BUCKET}.s3.amazonaws.com/${fileName}` };
      resolve();
    })
  })
});

顺便说一句,您可以使用Parse S3适配器并将PDF保存为常规解析文件,而不是使用AWS SDK。

这段代码会超时。通过在wait函数中添加
thisPDF.on('end',()
),我们是否将其从正常的流程中排除?您也可以在回调中添加其他行,但我认为这不是问题所在(只是编辑了答案)。尝试添加一些
控制台。记录
调用,查看
resolve
函数是否在某个时间点被调用。我将整个函数放在promise中,然后