簡體   English   中英

緩沖區中的 Blob 返回損壞的 pdf

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM