Home > OS >  Image missing with an Error: Cannot set header after they are sent to client
Image missing with an Error: Cannot set header after they are sent to client

Time:01-05

I converted my old Demo project to MVC style by separating model, view & control, added a new controller folder. All functionalities are working perfectly fine, except the storing of an image. I am getting an error: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client

I did some debugging & found out image is present during validation, but it is not present when it is sent to request handler to store the db object. Please check this image of debugging output

There is also a strange error in the DB. title, body & image path is getting inserted two times inside DB. I deleted the old stuff & tried it again & again. But still noticed, for one insertion using '/posts/new' page: two same objects is getting stored in mongodb. Image attached from Mongo DB compass

Here is the project flow: The request object with the image is picked from '/posts/new' page, validated in the validation middleware, if title & image are present: it will be sent to the request handler app.post('/posts/store', storePostController); which will store the image using path & it will store a mongo db document which contains title, body & image path inside the DB.

The code for the following is given below: 1) createPost.ejs

<!DOCTYPE html>
<html lang="en">
<!-- Header-->
<%- include('layouts/header'); -%>

    <body>
        <!-- Navigation-->
        <%- include('layouts/navbar'); -%>
            <!-- Page Header-->
            <header  style="background-image: url('/assets/img/contact-bg.jpg')">
                <div >
                    <div >
                        <div >
                            <div >
                                <h1>Create New Post</h1>
                            </div>
                        </div>
                    </div>
                </div>
            </header>
            <!-- Main Content-->
            <main >
                <div >
                    <div >
                        <div >
                            <div >
                                <form action="/posts/store" method="POST" enctype="multipart/form-data">
                                    <div >
                                        <input  id="title" name="title" type="text"
                                            placeholder="Enter the title..." />
                                        <label for="title">Title</label>
                                    </div>

                                    <div >
                                        <textarea  id="body" name="body" style="height: 12rem"
                                            placeholder="Enter your message here..." style="height: 12rem"></textarea>
                                        <label for="message">Description</label>
                                    </div>

                                    <div >
                                        <input  id="image" name="image" type="file"
                                            placeholder="Upload an image" />
                                        <label for="title">Image</label>
                                    </div>

                                    <!-- Submit Button-->
                                    <button id="submitButton" type="submit">Send</button>
                                </form>
                            </div>
                        </div>
                    </div>
                </div>
            </main>
            <!-- Footer-->
            <%- include('layouts/footer'); -%>
                <!-- Scripts-->
                <%- include('layouts/scripts'); -%>
    </body>

</html>

2) index.js

const express = require('express');
const ejs = require('ejs');
const mongoose = require('mongoose'); 
const fileUpload = require('express-fileupload');
//const { resourceUsage } = require('process');

mongoose.connect('mongodb://localhost/my_database', { useNewUrlParser: true }); //Defining a connection

const app = new express();
app.set('view engine', 'ejs');

const validateMiddleware = require('./middleware/validationMiddleware');
const homeController = require('./controllers/home');
const getPostController = require('./controllers/getPost');
const newPostController = require('./controllers/newPost');
const storePostController = require('./controllers/storePost');


app.use(express.static('public'));  
app.use(express.json());
app.use(express.urlencoded());
app.use(fileUpload());
app.use('/posts/store', validateMiddleware);


app.listen(4000, () => {
    console.log('App listening on port 4000');
});


app.get('/', homeController);

app.get('/post/:id', getPostController);

app.get('/posts/new', newPostController);

app.post('/posts/store', storePostController);

3) validationMiddleware.js

module.exports = (req, res, next) => {

    console.log("Executing Validation Middleware")  //Debugging code
    console.log(req.files)                          //Debugging code

    if (req.files == null || req.body.title == "") {

        return res.redirect('/posts/new');
    }
    next();
}

4) storePost.js

const path = require('path');
const BlogPost = require('../models/BlogPost');

module.exports = async (req, res) => {

    let image = req.files.image;

    console.log("Image Name: "   image.name);           //Debugging Code
    console.log("Printing Image : "   req.files.image); //Debugging Code

    image.mv(path.resolve(__dirname, 'public/img', image.name),
        async (error) => {
            await BlogPost.create({
                ...req.body,
                image: '/img/'   image.name
            })
            res.redirect('/');
        });

}
  1. Folder Structure Folder structure

CodePudding user response:

Try console req.files in the controller too instead of req.files.image once the debug again also try to convert validation to function() , export it and call it in the controller and use callbacks.

CodePudding user response:

The bug was, I was operating storePost.js from the controllers folder & I had copied the code from index.js which was in the root folder.

path.resolve() method was expecting one up folder & we had to pass an additional argument as '..' after __dirname

Observe the arguments supplied for path.resolve() method. The below code is the correct way to do it:

image.mv(path.resolve(__dirname, '..', 'public/img', image.name),
        async (error) => {
            await BlogPost.create({
                ...req.body,
                image: '/img/'   image.name
            })
            res.redirect('/');
        });

One small mistake gave a whole lot of errors, which I couldn't trace. Finally the error is resolved.

  •  Tags:  
  • Related