使用expressjs时,下载的.pdf文件已损坏



我正在使用生成的meanjs应用程序https://github.com/DaftMonk/generator-angular-fullstack.我正在尝试使用phantomjs生成一个.pdf文件并将其下载到浏览器。

问题是,无论页数多少,下载的.pdf文件总是显示空白页面。服务器上的原始文件未损坏。当我进一步调查时,发现下载的文件总是比磁盘上的原始文件大得多。同样,这个问题只发生在.pdf文件中。其他文件类型运行良好。

我尝试了几种方法,如res.redirect('http://localhost:9000/assets/exports/receipt.pdf');res.download('client\assets\exports\receipt.pdf')

var fileSystem = require('fs');
var stat = fileSystem.statSync('client\assets\exports\receipt.pdf');
res.writeHead(200, {
'Content-Type': 'application/pdf',
'Content-Length': stat.size
});
var readStream = fileSystem.createReadStream('client\assets\exports\receipt.pdf');
return readStream.pipe(res);

甚至我也试过https://github.com/expressjs/serve-static结果没有变化。

我是nodejs的新手。将.pdf文件下载到浏览器的最佳方式是什么?

更新:我在Windows 8.1 64位计算机上运行此程序

我在提供静态pdf时也发生了损坏。我尝试了上面建议的一切。然后我发现:https://github.com/intesso/connect-livereload/issues/39本质上,通常出色的连接livereload(包约0.4.0)正在破坏pdf。因此,只需通过忽略PDF即可

app.use(require('connect-livereload')({ignore: ['.pdf']}));

现在这个工作:

app.use('/pdf', express.static(path.join(config.root, 'content/files')));

如释重负。

这里有一种从express提供文件的干净方法,并使用attachment标头来确保文件已下载:

var path = require('path');
var mime = require('mime');
app.get('/download', function(req, res){
//Here do whatever you need to get your file
var filename = path.basename(file);
var mimetype = mime.lookup(file);
res.setHeader('Content-disposition', 'attachment; filename=' + filename);
res.setHeader('Content-type', mimetype);
var filestream = fs.createReadStream(file);
filestream.pipe(res);
});

有几种方法可以做到这一点:

  1. 如果文件是静态文件,如宣传册、自述等,那么你可以告诉express我的文件夹有静态文件(应该可以直接使用),并将文件保存在那里。这是使用静态中间件完成的:app.use(express.static(pathtofile));以下是链接:http://expressjs.com/starter/static-files.html

现在您可以使用浏览器中的url直接打开文件,如:

window.open('http://localhost:9000/assets/exports/receipt.pdf');

res.redirect('http://localhost:9000/assets/exports/receipt.pdf'); 

应该起作用。

  1. 第二种方法是读取文件,数据必须作为缓冲区。事实上,如果你直接发送它,它应该被识别,但你可以尝试使用将其转换为base64编码

    var base64String=buf.toString('base64');

然后设置内容类型:

res.writeHead(200, {
'Content-Type': 'application/pdf',
'Content-Length': stat.size
});

并发送数据作为响应。我将尝试举一个这样的例子。

编辑:你甚至不需要编码。你可以继续尝试。但我甚至不用编码就能让它工作

另外,您也不需要设置标题。Express为您服务。以下是API代码段,用于获取pdf,以防它不是公共/静态的。您需要API来提供pdf:

router.get('/viz.pdf', function(req, res){
require('fs').readFile('viz.pdf', function(err, data){
res.send(data);
})
});

最后,请注意,获取pdf的url有扩展名pdf,这是为了让浏览器识别传入文件是pdf。否则,它将保存没有任何扩展名的文件。

通常,如果您使用phantom生成pdf,则文件将被写入光盘,并且您必须向render函数提供路径和回调。

router.get('/pdf', function(req, res){
// phantom initialization and generation logic
// supposing you have the generation code above 
page.render(filePath, function (err) {
var filename = 'myFile.pdf';
res.setHeader('Content-type', "application/pdf");
fs.readFile(filePath, function (err, data) {
// if the file was readed to buffer without errors you can delete it to save space
if (err) throw err;
fs.unlink(filePath);
// send the file contents
res.send(data);
});
});
});

我对你提到的框架没有经验,但我建议使用Fiddler这样的工具来查看发生了什么。例如,你可能不需要添加内容长度标头,因为你正在流媒体传输,而你的框架进行分块传输编码等。

最新更新