通过Node.js API借助FTP从远程服务器下载PDF的问题
Got it, let's figure out why your PDF download isn't working! The main issue here is that you're treating a binary PDF file like a string—and that's breaking the data irreparably. PDFs are binary formats, so every byte matters. Converting them to a string (with toString()) uses text encoding (like UTF-8) that mangles raw binary values, resulting in a corrupted file when you try to download it.
Here's how to fix this step by step:
1. Stop using strings—use Buffers for binary data
Instead of concatenating strings, collect the raw binary chunks into an array of Buffers, then merge them into a single Buffer once the transfer is complete. This preserves the original PDF data.
2. Set proper HTTP headers for download
When sending the PDF to your website's frontend, you need to tell the browser exactly what it's receiving and that it should trigger a download (not try to display it as text).
Full working example (using Express as an example framework)
// Assuming you're using Express for your API const express = require('express'); const app = express(); const FTP = require('jsftp'); // Initialize your FTP client (fill in your credentials) const ftpClient = new FTP({ host: 'your-remote-server.com', user: 'your-ftp-username', pass: 'your-ftp-password' }); app.get('/download-pdf', (req, res) => { const pdfFilePath = 'path/to/my/file'; let binaryChunks = []; ftpClient.get(pdfFilePath, (err, socket) => { if (err) { console.error("Failed to start fetching PDF:", err); return res.status(500).send("Could not retrieve PDF file"); } // Collect raw binary chunks socket.on('data', (chunk) => binaryChunks.push(chunk)); socket.on('close', (err) => { if (err) { console.error("Error during PDF transfer:", err); return res.status(500).send("Error downloading PDF"); } // Merge chunks into a single Buffer const pdfBuffer = Buffer.concat(binaryChunks); // Set headers to trigger download res.setHeader('Content-Type', 'application/pdf'); res.setHeader( 'Content-Disposition', 'attachment; filename="my-document.pdf"' // Replace with your desired filename ); // Send the PDF data to the browser res.send(pdfBuffer); }); // Handle socket errors socket.on('error', (err) => { console.error("Socket error:", err); res.status(500).send("Connection error during download"); }); socket.resume(); }); }); app.listen(3000, () => console.log("API running on port 3000"));
Bonus: Optimize for large PDFs (streaming)
If your PDF is large, collecting all chunks in memory isn't efficient. Instead, you can pipe the FTP socket directly to the HTTP response to stream the data in real-time:
app.get('/download-pdf', (req, res) => { const pdfFilePath = 'path/to/my/file'; ftpClient.get(pdfFilePath, (err, socket) => { if (err) { return res.status(500).send("Could not retrieve PDF file"); } // Set headers first res.setHeader('Content-Type', 'application/pdf'); res.setHeader('Content-Disposition', 'attachment; filename="my-document.pdf"'); // Pipe the FTP socket directly to the response socket.pipe(res); socket.on('error', (err) => { console.error("Stream error:", err); res.status(500).send("Error streaming PDF"); }); socket.resume(); }); });
This avoids loading the entire file into memory, which is better for performance and server resources.
内容的提问来源于stack exchange,提问作者jean-max

