核心Node.js中Express的app.use()等价方案及无框架下用connect-mongo实现会话
Hey there! Since you're just getting started with raw Node.js backend development (no frameworks like Express), let's tackle your two questions clearly and practically.
app.use() in Raw Node.js First, let's recall what Express's app.use() does: it lets you mount middleware functions that run for every (or path-matched) incoming HTTP request, in the order you define them. Each middleware gets access to the request (req), response (res), and a next() function to pass control to the next middleware.
To replicate this in raw Node.js, we can create a simple wrapper around the core http module that maintains a list of middleware functions and executes them sequentially for each request. Here's a working example:
const http = require('http'); // Our custom "app" object to mimic Express's middleware pattern const app = { middleware: [], // Add middleware to our list (supports optional path matching) use(pathOrFn, fn) { if (typeof pathOrFn === 'function') { // If only a function is passed, default to matching all paths ('/') this.middleware.push({ path: '/', handler: pathOrFn }); } else { this.middleware.push({ path: pathOrFn, handler: fn }); } }, // Start the server and handle requests listen(port, callback) { const server = http.createServer((req, res) => { let middlewareIndex = 0; // The next() function to pass control to the next middleware function next() { if (middlewareIndex >= app.middleware.length) { // All middleware executed; send a default 404 if no response was sent if (!res.headersSent) { res.writeHead(404, { 'Content-Type': 'text/plain' }); res.end('404 - Not Found'); } return; } const { path, handler } = app.middleware[middlewareIndex++]; // Simple path matching: check if the request URL starts with the middleware's path if (req.url.startsWith(path)) { handler(req, res, next); } else { // Skip this middleware if the path doesn't match next(); } } // Kick off the middleware chain next(); }); server.listen(port, callback); } }; // Example usage of our custom app.use() app.use((req, res, next) => { console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`); next(); }); app.use('/hello', (req, res) => { res.writeHead(200, { 'Content-Type': 'text/plain' }); res.end('Hello from our custom middleware!'); }); app.listen(3000, () => { console.log('Server running on http://localhost:3000'); });
Key Details:
- The
use()method adds middleware to an array, supporting both path-specific and global middleware. - The
listen()method creates a Node.js HTTP server, and for each request, it runs through the middleware chain using thenext()function. - We include basic path matching to mimic Express's behavior, but you can expand this (e.g., support wildcards) if needed.
connect-mongo for Sessions in Raw Node.js connect-mongo is built to work with Express's express-session middleware, but we can adapt it for raw Node.js by manually handling session logic: parsing cookies, generating session IDs, and using connect-mongo as the session storage layer.
Step 1: Install Dependencies
First, install the required packages:
npm install connect-mongo cookie-parser
cookie-parsersimplifies parsing request cookies (you could do this manually, but it saves time).cryptois a core Node.js module we'll use for generating secure session IDs.
Step 2: Working Implementation
const http = require('http'); const { MongoStore } = require('connect-mongo'); const cookieParser = require('cookie-parser'); const crypto = require('crypto'); // Initialize the MongoDB session store const sessionStore = new MongoStore({ mongoUrl: 'mongodb://localhost:27017/your-db-name', // Replace with your MongoDB URI collectionName: 'sessions', ttl: 86400 // Session expires after 24 hours (in seconds) }); // Custom session middleware to mimic express-session function sessionMiddleware(req, res, next) { // First, parse the request cookies cookieParser()(req, res, () => { // Get the session ID from the cookie (matches express-session's default cookie name) let sessionId = req.cookies['connect.sid']; // If no session ID exists, generate a new secure one if (!sessionId) { sessionId = crypto.randomBytes(32).toString('hex'); // Set the session cookie (HttpOnly prevents XSS attacks) res.setHeader('Set-Cookie', `connect.sid=${sessionId}; HttpOnly; Path=/; Max-Age=${86400}`); } // Fetch the session data from MongoDB sessionStore.get(sessionId, (err, sessionData) => { if (err) return next(err); // Attach session data to the request object (like Express does) req.session = sessionData || {}; // Override res.end to save session data when the response finishes const originalEnd = res.end; res.end = function(data, encoding) { sessionStore.set(sessionId, req.session, (saveErr) => { if (saveErr) console.error('Failed to save session:', saveErr); originalEnd.call(this, data, encoding); }); }; // Move to the next middleware/request handler next(); }); }); } // Create our server and use the session middleware const server = http.createServer((req, res) => { sessionMiddleware(req, res, () => { // Handle different routes if (req.url === '/') { // Track page views with the session req.session.views = (req.session.views || 0) + 1; res.writeHead(200, { 'Content-Type': 'text/plain' }); res.end(`You've visited this page ${req.session.views} times!`); } else if (req.url === '/logout') { // Destroy the session sessionStore.destroy(sessionId, (err) => { if (err) console.error('Failed to destroy session:', err); // Clear the session cookie res.setHeader('Set-Cookie', 'connect.sid=; HttpOnly; Path=/; Expires=Thu, 01 Jan 1970 00:00:00 GMT'); res.writeHead(200, { 'Content-Type': 'text/plain' }); res.end('Logged out successfully!'); }); } else { res.writeHead(404, { 'Content-Type': 'text/plain' }); res.end('404 - Not Found'); } }); }); server.listen(3000, () => { console.log('Server running on http://localhost:3000'); });
Key Details:
- We initialize
MongoStorewith your MongoDB connection string and session TTL (time-to-live) for automatic session cleanup. - The
sessionMiddlewarehandles cookie parsing, session ID generation, fetching/saving session data to MongoDB. - We override
res.endto ensure session data is saved when the response is sent, just like Express's session middleware does. - Make sure your MongoDB server is running before starting the Node.js server!
内容的提问来源于stack exchange,提问作者Hakimuddin




