如何在 Firebase 文件系统中临时存储 pdf?
How can I temporarily store a pdf in Firebase filesystem?
我正在服务器端使用 JSPDF 在 NodeJS 中创建一个 pdf。完成后,我想在 Google Drive 中为用户创建一个新文件夹,将 pdf 上传到该文件夹,并将其发送到客户端(浏览器)供用户查看。
我遇到了两个问题。首先,如果我在响应中发送 pdf - 通过 pdf.output() - 图像无法正确显示。它们是扭曲的,就好像每行像素都偏移了一定量。竖线“|”而是呈现为对角线“\”。示例如下所示。
之前
之后
我的解决方法是使用 doc.save() 将其保存到文件系统,然后使用 fs.readFileSync(文件路径) 将其发送到浏览器。
但是,我发现当 运行 远程时,我没有文件权限来保存和阅读 pdf。经过一些研究和修补,我认为我无法更改这些权限。这是我得到的错误:
错误:EROFS:只读文件系统,打开'./temp/output.pdf'
在 Object.openSync (fs.js:443:3)
在 Object.writeFileSync (fs.js:1194:35)
在 Object.v.save (/workspace/node_modules/jspdf/dist/jspdf.node.min.js:86:50626)
等...
所以我有这个 JSPDF 对象,我相信我需要要么更改允许 writing/reading 的权限,要么获取 jspdf 对象,或者,我想,将其格式更改为 [=63 接受的格式=] 驱动器,例如流或缓冲区对象?
下面的 link 让我认为这些权限无法更改,因为它指出:“这些文件在只读目录中可用”。
https://cloud.google.com/functions/docs/concepts/exec#file_system
我也不知道 'where' 服务器文件系统是什么,或者如何访问它。因此,我认为最好的做法是考虑发送不同格式的 pdf。
我已经检查了 jsPDF 文档中 pdf.output() 可以 return 的类型。这些包括字符串、arraybuffer、window、blob、jsPDF。
https://rawgit.com/MrRio/jsPDF/master/docs/jsPDF.html#output
我的简化代码如下:
const express = require('express');
const fs = require('fs');
const app = express();
const { jsPDF } = require('jspdf');
const credentials = require(credentialsFilepath);
const scopes = [scopes in here];
const auth = new google.auth.JWT(
credentials.client_email, null,
credentials.private_key, scopes
);
const drive = google.drive({version: 'v3', auth});
//=========================================================================
app.post('/submit', (req, res) => {
var pdf = new jsPDF();
// Set font, fontsize. Added some text, etc.
pdf.text('blah blah', 10, 10);
// Add image (signature) from canvas, which is passed as a dataURL
pdf.addImage(img, 'JPEG', 10, 10, 50, 20);
pdf.save('./temp/output.pdf');
drive.files.create({
resource: folderMetaData,
fields: 'id'
})
.then(response => {
// Store pdf in newly created folder
var fileMetaData = {
'name': 'filename.pdf',
'parents': [response.data.id],
};
var media = {
mimeType: 'application/pdf',
body: fs.createReadStream('./temp/output.pdf'),
};
drive.files.create({
resource: fileMetaData,
media: media,
fields: 'id'
}, function(err, file) {
if(err){
console.error('Error:', err);
}else{
// I have considered piping 'file' back in the response here but can't figure out how
console.log('File uploaded');
}
});
})
.catch(error => {
console.error('Error:', error);
});
// Finally, I attempt to send the pdf to client/browser
res.setHeader('Content-Type', 'application/pdf');
res.send(fs.readFileSync('./temp/output.pdf'));
})
编辑:经过更多搜索,我发现了一个类似的问题,它解释了 fs 模块用于 reading/writing 到本地文件存储。
经过进一步阅读,我最终找到了解决方案。我不确定这对谁有用,但是...
原来 Firebase 文件系统只有 1 个目录允许您写入(其余的都是只读的)。该目录名为 tmp,我使用 tmp 节点模块访问它 [安装方式:npm i tmp],因为尝试使用 pdf.save('./tmp/output.pdf') 手动引用路径没有'没用。
所以对我的代码所做的唯一更改是添加以下行:
var tmp = require('tmp');
var tmpPath = tmp.tmpNameSync();
然后将 './temp/output.pdf' 的所有实例替换为 tmpPath
我正在服务器端使用 JSPDF 在 NodeJS 中创建一个 pdf。完成后,我想在 Google Drive 中为用户创建一个新文件夹,将 pdf 上传到该文件夹,并将其发送到客户端(浏览器)供用户查看。
我遇到了两个问题。首先,如果我在响应中发送 pdf - 通过 pdf.output() - 图像无法正确显示。它们是扭曲的,就好像每行像素都偏移了一定量。竖线“|”而是呈现为对角线“\”。示例如下所示。
之前
之后
我的解决方法是使用 doc.save() 将其保存到文件系统,然后使用 fs.readFileSync(文件路径) 将其发送到浏览器。 但是,我发现当 运行 远程时,我没有文件权限来保存和阅读 pdf。经过一些研究和修补,我认为我无法更改这些权限。这是我得到的错误:
错误:EROFS:只读文件系统,打开'./temp/output.pdf'
在 Object.openSync (fs.js:443:3)
在 Object.writeFileSync (fs.js:1194:35)
在 Object.v.save (/workspace/node_modules/jspdf/dist/jspdf.node.min.js:86:50626)
等...
所以我有这个 JSPDF 对象,我相信我需要要么更改允许 writing/reading 的权限,要么获取 jspdf 对象,或者,我想,将其格式更改为 [=63 接受的格式=] 驱动器,例如流或缓冲区对象?
下面的 link 让我认为这些权限无法更改,因为它指出:“这些文件在只读目录中可用”。
https://cloud.google.com/functions/docs/concepts/exec#file_system
我也不知道 'where' 服务器文件系统是什么,或者如何访问它。因此,我认为最好的做法是考虑发送不同格式的 pdf。
我已经检查了 jsPDF 文档中 pdf.output() 可以 return 的类型。这些包括字符串、arraybuffer、window、blob、jsPDF。
https://rawgit.com/MrRio/jsPDF/master/docs/jsPDF.html#output
我的简化代码如下:
const express = require('express');
const fs = require('fs');
const app = express();
const { jsPDF } = require('jspdf');
const credentials = require(credentialsFilepath);
const scopes = [scopes in here];
const auth = new google.auth.JWT(
credentials.client_email, null,
credentials.private_key, scopes
);
const drive = google.drive({version: 'v3', auth});
//=========================================================================
app.post('/submit', (req, res) => {
var pdf = new jsPDF();
// Set font, fontsize. Added some text, etc.
pdf.text('blah blah', 10, 10);
// Add image (signature) from canvas, which is passed as a dataURL
pdf.addImage(img, 'JPEG', 10, 10, 50, 20);
pdf.save('./temp/output.pdf');
drive.files.create({
resource: folderMetaData,
fields: 'id'
})
.then(response => {
// Store pdf in newly created folder
var fileMetaData = {
'name': 'filename.pdf',
'parents': [response.data.id],
};
var media = {
mimeType: 'application/pdf',
body: fs.createReadStream('./temp/output.pdf'),
};
drive.files.create({
resource: fileMetaData,
media: media,
fields: 'id'
}, function(err, file) {
if(err){
console.error('Error:', err);
}else{
// I have considered piping 'file' back in the response here but can't figure out how
console.log('File uploaded');
}
});
})
.catch(error => {
console.error('Error:', error);
});
// Finally, I attempt to send the pdf to client/browser
res.setHeader('Content-Type', 'application/pdf');
res.send(fs.readFileSync('./temp/output.pdf'));
})
编辑:经过更多搜索,我发现了一个类似的问题,它解释了 fs 模块用于 reading/writing 到本地文件存储。
经过进一步阅读,我最终找到了解决方案。我不确定这对谁有用,但是...
原来 Firebase 文件系统只有 1 个目录允许您写入(其余的都是只读的)。该目录名为 tmp,我使用 tmp 节点模块访问它 [安装方式:npm i tmp],因为尝试使用 pdf.save('./tmp/output.pdf') 手动引用路径没有'没用。
所以对我的代码所做的唯一更改是添加以下行:
var tmp = require('tmp');
var tmpPath = tmp.tmpNameSync();
然后将 './temp/output.pdf' 的所有实例替换为 tmpPath