Node.js中ERR_HTTP_HEADERS_SENT错误排查及Helmet配置咨询
Hey there, let's break down your issues one by one and fix them up!
一、解决 Error [ERR_HTTP_HEADERS_SENT] 错误
错误根源
Your code has a classic Express mistake: you're sending two HTTP responses for a single request. When Joi validation fails, you call res.send('an error occured') but don't stop the function from running. The code then proceeds to the next res.send("successfully added"), forcing Express to try sending headers twice—this is exactly what triggers the ERR_HTTP_HEADERS_SENT error.
Plus, there's a tiny variable mismatch that would have broken your validation anyway: your request body has summary, but you're trying to pull summaries from it. Let's fix both issues.
修正后的代码
exports.addbooks = function (req, res) { // Fix variable name to match request body const bookname = req.body.bookname; const summaries = req.body.summary; const isbn = req.body.isbn; const category = req.body.select; const schema = Joi.object().keys({ bookname: Joi.string().trim().min(6).max(25).required(), summaries: Joi.string().trim().required(), isbn: Joi.number().required(), category: Joi.string().trim().required() }); Joi.validate(req.body, schema, (err, result) => { if (err) { // Print error details instead of undefined result console.log('Validation error:', err.details[0].message); // Use return to stop execution after sending error response return res.send(`Validation failed: ${err.details[0].message}`); } console.log('Validated data:', result); // Perform Knex insert asynchronously (critical to avoid blocking) knex('books') .insert({ bookname: result.bookname, summaries: result.summaries, isbn: result.isbn, category: result.category }) .then(() => { res.send("Successfully added book to database"); }) .catch(dbErr => { res.send(`Database error: ${dbErr.message}`); }); }); }
关键修正点
- Added
returnafter the error response to prevent the code from reaching the secondres.send - Fixed the variable mismatch between
req.body.summaryand yoursummariesvariable - Wrapped the Knex insert in a promise chain to handle async database operations properly
- Updated error logging to show useful validation details instead of undefined values
Note: If you're using Joi v16+, the Joi.validate() method is deprecated—switch to schema.validate(req.body) instead for future compatibility.
二、Helmet 使用指南
Helmet is an Express middleware that automatically sets secure HTTP headers to protect your app from common web vulnerabilities (like XSS, clickjacking, and MIME sniffing). It's super easy to set up:
Step 1: Install Helmet
Run this in your project root:
npm install helmet
Step 2: Integrate with Your Express App
Add Helmet early in your middleware stack to ensure security headers are applied to all requests:
const express = require('express'); const helmet = require('helmet'); const app = express(); // Use Helmet before other middleware/routes app.use(helmet()); // Continue with your existing setup app.use(express.urlencoded({ extended: true })); // Add your routes here (like /addbooks) app.listen(3000, () => { console.log('Server running on port 3000 with Helmet security headers'); });
Optional Customization
Helmet enables sensible default headers, but you can tweak settings if needed:
app.use(helmet({ // Disable a specific header if you have a use case for it frameguard: false, // Customize Content Security Policy (CSP) rules contentSecurityPolicy: { directives: { defaultSrc: ["'self'"], scriptSrc: ["'self'", "'unsafe-inline'"] // Only use unsafe-inline if absolutely necessary } } }));
The default configuration works for most apps, so you can stick with that unless you have specific security requirements.
内容的提问来源于stack exchange,提问作者dokunbam

