[英]Blob from buffer returns corrupted pdf
尝试在 Firebase 函数上使用 Puppeteer 制作 pdf:发送 html 片段,返回 pdf。
但是pdf已损坏。 我认为问题在于返回文件/缓冲区。
// Server:
// setup
const func = require('firebase-functions');
const pptr = require('puppeteer');
const opts = { memory: '1GB', regions: ['europe-west3'] };
const call = func.runWith(opts).https.onCall
let browser = pptr.launch({ args: ['--no-sandbox'] });
// onCall
exports.makePdf = call(async (data) => {
// this works, does open the page testing with { headless: false }
const brws = await (await browser).createIncognitoBrowserContext();
const page = await brws.newPage();
await page.setContent(data, { waitUntil: 'domcontentloaded' });
const file = await page.pdf({ format: 'A4' });
await brws.close();
// the problem is returning the file
return file
});
当file
记录在服务器上时,它是一个缓冲区<Buffer 25 50 44 46 2d 31 2e ... 11150 more bytes>
,但当登录到客户端时,它是一个对象,以十进制而不是十六进制{ data: {0: 37, 1: 80, 2: 68, 3: 70, ... }}
。
将其转换回缓冲区? 转换回十六进制? 哪个缓冲区?
// Client:
// send html and receive the file
let html = '<div><h1>Hi</h1></div>';
let file = ((await fns.makePdf(html))).data;
// also tried buffer = new Buffer.from(JSON.stringify(file));
let blob = new Blob(file, { type: 'application/pdf' });
// download the file
let a = document.createElement('a');
a.href = window.URL.createObjectURL(blob);
a.download = `${name}.pdf`;
a.click();
还是因为我下载错误( createObjectURL
)而导致 pdf 损坏? 或者 onCall 函数不能这样使用?
重点是,不知道为什么它不起作用。 谢谢你的帮助
好的。 /插入诅咒众神/
所以没关系,您可以使用 onCall 而不是 onRequest,因为您最终可以从 json 响应创建一个 pdf。 onCall 好一点的原因是因为你不需要打扰 cors 或 headers,谷歌为你做。
// setup
const func = require('firebase-functions');
const pptr = require('puppeteer');
const opts = { memory: '1GB', regions: ['europe-west3'] };
const call = func.runWith(opts).https.onCall
// this runs outside of the function because it might not be killed off
// if the function is called quickly in succession (lookup details on
// google cloud functions docs)
let browser = pptr.launch({ args: ['--no-sandbox'] });
// the main function
exports.makePdf = call(async (data) => {
// prep puppeteer so it can print the pdf
const brws = await (await browser).createIncognitoBrowserContext();
const page = await brws.newPage();
await page.setContent(data);
const file = await page.pdf({
format: 'A4',
printBackground: false,
margin: { left: 0, top: 0, right: 0, bottom: 0 }
});
brws.close();
// and just return the stream
return file
});
诀窍在于客户端。 我会在评论中注明。
// so this is inside some function, has to be because it needs to be async
var a, blob, buffer, d, file, html, i, result;
// this html is for testing, it would obviously be gathered in another way
html = '<div><h1>Hi</h1></div>';
// we call the function from the client
// fns is my shorthand object defined on Google Functions initialization
// it is literally: f.httpsCallable('makePdf') where f is the functions object
// you get from initialization
file = ((await fns.makePdf(html))).data;
// additional .data is needed because onCall automatically wraps
// now the point
// 1. convert object to array
result = []; for (i in file) {
d = file[i]; result.push(d);
}
// 2. convert that to a Uint8Array
buffer = new Uint8Array(result);
// 3. create a blob, BUT the buffer needs to go inside another array
blob = new Blob([buffer], { type: 'application/pdf' });
// finally, download it
a = document.createElement('a');
a.href = window.URL.createObjectURL(blob);
a.download = `${path}.pdf`;
a.click();
我发现这个项目与你的相似,我发现了一个不同之处,在缓冲区返回中你需要指定标头和 HTTP 代码,客户端浏览器可能会误解来自服务器的对象。
这是另一个项目的返回段
const pdfBuffer = await page.pdf({ printBackground: true });
res.set("Content-Type", "application/pdf");
res.status(200).send(pdfBuffer);
代码中的所有内容看起来都正确,如果将 PDF 从 dec 转换为 hex 返回相同的字符串,我认为这可能是一个很好的解决方法。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.