如何在Express.js中实现无页面跳转的请求获取及文件系统操作?
Hey there! Let's break down how to solve your two related problems—keeping your page from navigating away while handling file system operations in Express. Here's a step-by-step solution tailored to your existing code:
Why Your Current Code Triggers Page Jumps
Right now, your /todo/download and /todo/upload routes send back plain text ("download page") which would replace your current page if accessed via a link or form submit. Instead, we need to:
- Use asynchronous requests from the frontend (so the browser doesn't reload)
- Update the Express routes to handle actual file system work and return responses that play nice with those async calls
Step 1: Refactor Your Express Backend
Let's adjust your code to handle real file operations and return appropriate responses:
let express = require('express'); let fs = require('fs'); // Lowercase for standard JS convention let path = require('path'); let app = express(); let router = express.Router(); const port = 2020; // Add middleware to parse request data (critical for uploads) app.use(express.static('Programs')); app.use(express.json()); // Parse JSON request bodies app.use(express.urlencoded({ extended: true })); // Parse form data app.use('/', router); // Serve your main page (unchanged) router.get('/', (req, res) => { res.sendFile(path.join(__dirname + '/views/UiOfServer.html')); }); // Handle download: Stream a file to the client without page reload router.get('/todo/download', (req, res) => { // Replace this with your actual file path const targetFile = path.join(__dirname, '/storage/your-file-to-download.txt'); // First check if the file exists fs.access(targetFile, fs.constants.F_OK, (err) => { if (err) { return res.status(404).json({ success: false, message: 'File not found' }); } // Set headers to trigger a download prompt without page change res.setHeader('Content-Disposition', 'attachment; filename="my-download.txt"'); res.setHeader('Content-Type', 'text/plain'); // Stream the file to the client (efficient for large files) const fileStream = fs.createReadStream(targetFile); fileStream.pipe(res); }); }); // Handle upload: Save content to the filesystem router.post('/todo/upload', (req, res) => { // For this example, we'll accept text content from the frontend // For binary files, use the `multer` package (see tip below) const uploadText = req.body.uploadContent; const savePath = path.join(__dirname, '/uploads/saved-upload.txt'); fs.writeFile(savePath, uploadText, (err) => { if (err) { return res.status(500).json({ success: false, message: 'Failed to save file' }); } res.json({ success: true, message: 'File uploaded successfully!' }); }); }); app.listen(port, (err) => { if(err){ console.log(`Server Error: ${err}`); } else{ console.log(`Server running on port ${port}`); } });
Step 2: Update Your Frontend (UiOfServer.html)
Add JavaScript to your HTML to handle button clicks with fetch—this sends requests in the background without reloading the page:
<!DOCTYPE html> <html> <head> <title>Server File Ops</title> </head> <body> <h1>File Operations</h1> <button id="downloadBtn">Download File</button> <div style="margin: 20px 0;"> <textarea id="uploadInput" rows="5" cols="50" placeholder="Enter text to upload..."></textarea> <br> <button id="uploadBtn">Upload Text</button> </div> <div id="statusMessage" style="color: blue;"></div> <script> const downloadBtn = document.getElementById('downloadBtn'); const uploadBtn = document.getElementById('uploadBtn'); const statusMsg = document.getElementById('statusMessage'); const uploadInput = document.getElementById('uploadInput'); // Handle Download Click downloadBtn.addEventListener('click', async () => { try { const response = await fetch('/todo/download'); if (!response.ok) throw new Error('Download failed'); // Convert response to blob and trigger browser download const blob = await response.blob(); const downloadUrl = window.URL.createObjectURL(blob); const link = document.createElement('a'); link.href = downloadUrl; link.download = 'my-download.txt'; document.body.appendChild(link); link.click(); // Clean up window.URL.revokeObjectURL(downloadUrl); document.body.removeChild(link); statusMsg.textContent = 'Download started successfully!'; } catch (err) { statusMsg.textContent = `Error: ${err.message}`; } }); // Handle Upload Click uploadBtn.addEventListener('click', async () => { const content = uploadInput.value.trim(); if (!content) { statusMsg.textContent = 'Please enter text to upload first!'; return; } try { const response = await fetch('/todo/upload', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ uploadContent: content }) }); const result = await response.json(); statusMsg.textContent = result.message; if (result.success) uploadInput.value = ''; // Clear input on success } catch (err) { statusMsg.textContent = `Upload error: ${err.message}`; } }); </script> </body> </html>
Quick Extra Tips
- Binary File Uploads: If you need to upload actual files (images, PDFs, etc.), use the
multernpm package in Express—it handles multipart/form-data requests seamlessly. - Error Handling: The code includes basic error handling to give users feedback without breaking the page. You can expand this to fit your needs.
- Security: Always validate and sanitize user input/file paths to prevent path traversal attacks (never use raw user input to construct file paths directly!).
内容的提问来源于stack exchange,提问作者Hessam Hosseini
相关产品推荐
相关产品推荐

