Related
trying to write a post request body to a text file using node js file system but i keep on getting this error and i don't even know what it means : Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at new NodeError (node:internal/errors:393:5)
at ServerResponse.setHeader (node:_http_outgoing:644:11)
can any one help? here is my code
var express = require('express');
var router = express.Router();
const message_control_post = require('../controllers/messageControl.js')
const { body, validationResult } = require('express-validator')
const fs = require('fs')
const fsPromises = require('fs').promises
const path = require('path')
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index');
});
router.post('/', message_control_post.message_control)
router.post('/test', (req, res, next) => {
const message = `${req.body.name} sent ${req.body.email} this message: ${req.body.msg}`
fs.writeFile(path.join(__dirname, 'files', 'msg.txt'), message, (err) => {
if (err) {
return next(err)
} else {
console.log(message)
}
})
next()
}, (req, res, next) => {
res.send(req.body)
});
The callback - last param of fs.writeFile will be called after the next(). So here the flow of your code:
fs.writeFile -> next -> res.send -> next(err) -> res.send
The second res.send then throw an Error [ERR_HTTP_HEADERS_SENT]
I think your code should look like this:
router.post('/test', (req, res) => {
const message = `${req.body.name} sent ${req.body.email} this message: ${req.body.msg}`
fs.writeFile(path.join(__dirname, 'files', 'msg.txt'), message, (err) => {
if (err) {
return res.send(error);
} else {
res.send(req.body)
}
})
});
I'm trying to execute a post function that has a next(); in the middle of the code, so i'm exporting the definition of the function from another file and trying to call it from express router. But it doesn't execute.
--EDIT
I've tried the regular definition as suggested above, but it stops when "next();" is called and returns
Cannot POST /registerUser
index.js
[...]
//Definição e Chamada de Componentes
const userLogin = require('./userControl/accessControl');
const userRegister = require('./userControl/registerControl');
[...]
var router = express.Router(); // get an instance of the express Router
//Definição das Rotas
//==============================================================================
router.post('/login', userLogin.login);
router.post('/forgotPassword', userLogin.forgotPassword);
router.post('/registerUser', function(req, res, next) {userRegister.registerUser});
app.use('/', router);
// START THE SERVER
// =============================================================================
app.set('env', 'production');
app.listen(port);
console.log('API Listening on Port ' +port+'');
registerControl.js
exports.registerUser = function(req, res, next) {
var query = "INSERT INTO [user] (name, email, phone, login, password, enabled, profile) VALUES ('example', 'example#abc.si', 'XXXXXXXXXXXX', 'ADMIN', '12345', 1, 'TEST')
global.conn.request()
.query(query)
.then(result => {
var userId = result.recordset[0].id;
console.log(userId);
if (result.rowsAffected[0] == 0) {
res.sendStatus(500);
}
else {
req.body.userId = userId;
next();
}
})
.catch(err => res.json(err));
}, function(req, res) {
var query = "INSERT INTO [user_company] (company_id, user_id) VALUES ("+req.body.companyId+", "+req.body.userId+");"
global.conn.request()
.query(query)
.then(result => {
if (result.rowsAffected[0] == 0) {
res.sendStatus(500);
}
else {
res.sendStatus(200);
}
})
.catch(err => res.json(err));
};
Thanks!
Instead of
router.post('/registerUser', function(req, res, next)
{userRegister.registerUser});
maybe try
router.post('/registerUser', userRegister.registerUser);
Just like you did in the above forgotPassword route.
// state edit route
app.get("/map/:symbol/edit", isLoggedIn, function(req, res){
State.findOne({symbol: req.params.symbol}, function(err, state){
if(err){
console.log(err);
} else
{
res.render("edit", {state: state});
}
});
});
In the above code snippet, isLoggedIn is the middleware function to check for authentication. Its definition is given below:
// middleware function
function isLoggedIn(req, res, next){
if(req.isAuthenticated()){
return next();
}
res.redirect("/admin");
}
So, the question is, how to pass a parameter like a string, an integer or a path variable to the middleware function so that it can be used in the routing url ?
I had the same requirement and this approach works for me.
Middleware file validate.js
exports.grantAccess = function(action, resource){
return async (req, res, next) => {
try {
const permission = roles.can(req.user.role)[action](resource);
// Do something
next();
}
catch (error) {
next(error)
}
}
}
Use of middleware in route file. grantAccess('readAny', 'user')
router.get("/",grantAccess('readAny', 'user'), async (req,res)=>{
// Do something
});
Follow this approach, it might do the job for you
app.use(function(req, res, next){
console.log(req);
this.req = req;
// assign value like this
this.req.body.custom_data = ['zz', 'aaa', ....];
next();
});
app.get("/map/:symbol/edit", isLoggedIn, function(req, res){
State.findOne({symbol: req.params.symbol}, function(err, state){
if(err){
console.log(err);
} else {
res.render("edit", {state: state});
}
});
});
function isLoggedIn(req, res, next){
console.log(req.body);
if(req.isAuthenticated()){
return next();
}
res.redirect("/admin");
}
This is the way I'm using it, I take a little bit of Hardik Raval answer.
helpers.validateRole = (roles) => {
return async (req, res, next) => {
try {
const authHeader = req.headers['authorization']
const token = authHeader && authHeader.split(' ')[0]
if (token == null) return res.json({error:true, msg: "Unauthorized"})
const user = jwt.decode(token)
let isValid = false
roles.map((r,i)=>{
if (r === user.role){
isValid = true
}
})
if (isValid){
// User role is valid
next();
}else{
// User role is not valid
util.returnError("Unauthorized", res);
}
}
catch (error) {
next(error)
}
}
}
And I called like this.
router.get( "/requirements/list_of_requirements/:page/:rows", isAuthenticated, validateRole([6]), async (req, res) => {
//* All the logic
})
I am using Node.JS Express and socket.io.
So my idea was to emit the message directly from my controller’s insert-method. In my server.js file, iam creating the socket.io object and try to make it accessible for other modules:
My server.js is like this
require('rootpath')();
var express = require('express');
var app = express();
var cors = require('cors');
var bodyParser = require('body-parser');
var expressJwt = require('express-jwt');
var config = require('config.json');
var mongoose = require('mongoose');
mongoose.connect(config.connectionString);
var db = mongoose.connection;
db.on('error',console.error.bind(console,'Connection error'));
db.on('open',function(){
console.log('connected');
});
app.use(cors());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
// use JWT auth to secure the api, the token can be passed in the authorization header or querystring
app.use(expressJwt({
secret: config.secret,
getToken: function (req) {
if (req.headers.authorization && req.headers.authorization.split(' ')[0] === 'Bearer') {
return req.headers.authorization.split(' ')[1];
} else if (req.query && req.query.token) {
return req.query.token;
}
return null;
}
}).unless({
path: [
'/users/authenticate',
'/users/register',
'/users',
'/chats','/chats/sendMessage',
'/rooms','/rooms/create',
'/chats/connection',
'/chats/add-message'
]
}));
// routes
app.use('/users', require('./controllers/users.controller'));
app.use('/chats', require('./controllers/chats.controller'));
app.use('/rooms', require('./controllers/rooms.controller'));
var http = require('http').Server(app);
var io = require('socket.io')(http);
io.on('connection', (socket) => {
console.log('The user is connected');
socket.on('new-message', (message,userInfo) => {
console.log(userInfo);
console.log(message);
io.emit('message', {type:'new-message', text: message});
});
socket.on('disconnect', function(){
console.log('The user is disconnected');
});
socket.on('add-message', (message,userInfo) => {
console.log(userInfo);
console.log(message);
io.emit('message', {type:'new-message', text: message});
});
socket.on('add-record', (record) => {
io.emit('getrecord', {type:'new-record', text: record});
});
});
// start server
var port = process.env.NODE_ENV === 'production' ? 80 : 4000;
var server = http.listen(port, function () {
console.log('Server listening on port ' + port);
});
Client - Data received
Emit welcome message on connection
how can i use this below socket connection in chat.controller.js
io.on('connection', (socket) => {
console.log('The user is connected');
socket.on('new-message', (message,userInfo) => {
console.log(userInfo);
console.log(message);
io.emit('message', {type:'new-message', text: message});
});
socket.on('disconnect', function(){
console.log('The user is disconnected');
});
socket.on('add-message', (message,userInfo) => {
console.log(userInfo);
console.log(message);
io.emit('message', {type:'new-message', text: message});
});
socket.on('add-record', (record) => {
io.emit('getrecord', {type:'new-record', text: record});
});
});
and i am creating controller file like this
chats.controller.js
var config = require('config.json');
var express = require('express');
var router = express.Router();
var userService = require('../services/user.service');
var chatService = require('../services/chat.service');
// routes
router.post('/sendMessage', send);
router.get('/', getAll);
module.exports = router;
function send(req, res) {
chatService.sendMessage(req.body)
.then(function () {
res.sendStatus(200);
})
.catch(function (err) {
res.status(400).send(err);
});
}
function getAll(req, res) {
chatService.getAllMessage()
.then(function (chats) {
res.send(chats);
})
.catch(function (err) {
res.status(400).send(err);
});
}
function getCurrent(req, res) {
userService.getById(req.user.sub)
.then(function (user) {
if (user) {
res.send(user);
} else {
res.sendStatus(404);
}
})
.catch(function (err) {
res.status(400).send(err);
});
}
function update(req, res) {
userService.update(req.params._id, req.body)
.then(function () {
res.sendStatus(200);
})
.catch(function (err) {
res.status(400).send(err);
});
}
function _delete(req, res) {
userService.delete(req.params._id)
.then(function () {
res.sendStatus(200);
})
.catch(function (err) {
res.status(400).send(err);
});
}
And also i have created one service file
name is chat.service.js
var config = require('config.json');
var _ = require('lodash');
var jwt = require('jsonwebtoken');
var bcrypt = require('bcryptjs');
var Q = require('q');
var mongoose = require('mongoose');
var Chat = require('../model/chat');
var service = {};
service.sendMessage = sendMessage;
service.getAllMessage = getAllMessage;
module.exports = service;
function sendMessage(userParam) {
var deferred = Q.defer();
var chat = new Chat({
room_id:userParam.from_id,
from_id:userParam.from_id,
to_id:userParam.to_id,
chatrp_id:userParam.chatrp_id,
message:userParam.message
});
chat.save(function (err,doc) {
if (err) deferred.reject(err.name + ': ' + err.message);
deferred.resolve();
})
return deferred.promise;
}
function getAllMessage() {
var deferred = Q.defer();
Chat.find({},function (err, response) {
if (err) deferred.reject(err.name + ': ' + err.message);
// return users (without hashed passwords)
response = _.map(response, function (res) {
return _.omit(res, 'hash');
});
deferred.resolve(response);
});
return deferred.promise;
}
But is is neither giving me an error or not working.
Can anyone please help, how can I export that in a separate file so that client and server code can be separated?
Thanks in advance for helping.
This how I got this to work.
Steps are as follows:
1) I created a utils folder, inside which I created a file named socket.js
utils/socket.js
const Server = require('socket.io');
const io = new Server();
var Socket = {
emit: function (event, data) {
console.log(event, data);
io.sockets.emit(event, data);
}
};
io.on("connection", function (socket) {
console.log("A user connected");
});
exports.Socket = Socket;
exports.io = io;
2) Then in my server(app.js) I did this
app.js
const app = express();
const server = http.createServer(app);
const { io } = require("./utils/socket");
io.attach(server);
module.exports = app;
3)After this 2 steps, In your controller file or any other file(s) where you need to emit an event, you can then just do this:
const { Socket } = require("../../utils/socket");
Socket.emit("newMessage", {
message: "hello from controller"
});
To emit messages from your controllers, the controllers need to have access to the original socket.io instance.
So, in chats.controller.js I would do like this:
module.exports = function(io){
return {
function: getAll(req, res){
// here you now have access to socket.io.
// you can either do:
io.emit('new-message',{
// new message object
});
// or you can include your chat service the same way
// that this file is included and call the appropriate function
},
}
};
To use this controller, just do
const someController = require('./path/to/chats.controller.js')(io);
You can do exactly the same in your service file.
I want to catch the error from the bodyParser() middleware when I send a json object and it is invalid because I want to send a custom response instead of a generic 400 error.
This is what I have and it works:
app.use (express.bodyParser ());
app.use (function (error, req, res, next){
//Catch bodyParser error
if (error.message === "invalid json"){
sendError (res, myCustomErrorMessage);
}else{
next ();
}
});
But this seems to me a very ugly approach because I'm comparing the error message which could change in future express versions. There's any other way to catch bodyParser() errors?
EDIT:
This is the error when the request body has an invalid json:
{
stack: 'Error: invalid json\n at Object.exports.error (<path>/node_modules/express/node_modules/connect/lib/utils.js:55:13)\n at IncomingMessage.<anonymous> (<path>/node_modules/express/node_modules/connect/lib/middleware/json.js:74:71)\n at IncomingMessage.EventEmitter.emit (events.js:92:17)\n at _stream_readable.js:872:14\n at process._tickDomainCallback (node.js:459:13)',
arguments: undefined,
type: undefined,
message: 'invalid json',
status: 400
}
Pretty printed stack:
Error: invalid json
at Object.exports.error (<path>/node_modules/express/node_modules/connect/lib/utils.js:55:13)
at IncomingMessage.<anonymous> (<path>/node_modules/express/node_modules/connect/lib/middleware/json.js:74:71)
at IncomingMessage.EventEmitter.emit (events.js:92:17)
at _stream_readable.js:872:14
at process._tickDomainCallback (node.js:459:13)
I think your best bet is to check for SyntaxError:
app.use(function (error, req, res, next) {
if (error instanceof SyntaxError) {
sendError(res, myCustomErrorMessage);
} else {
next();
}
});
From the answer of #alexander but with an example of usage
app.use((req, res, next) => {
bodyParser.json({
verify: addRawBody,
})(req, res, (err) => {
if (err) {
console.log(err);
res.sendStatus(400);
return;
}
next();
});
});
function addRawBody(req, res, buf, encoding) {
req.rawBody = buf.toString();
}
what I did was just:
app.use(bodyParser.json({ limit: '10mb' }))
// body parser error catcher
app.use((err, req, res, next) => {
if (err) {
res.status(400).send('error parsing data')
} else {
next()
}
})
Ok, found it:
bodyParser() is a convenience function for json(), urlencoded() and multipart(). I just need to call to json(), catch the error and call to urlencoded() and multipart().
bodyParser source
app.use (express.json ());
app.use (function (error, req, res, next){
//Catch json error
sendError (res, myCustomErrorMessage);
});
app.use (express.urlencoded ());
app.use (express.multipart ());
All errors include a type property from 1.18.0 release onwards. For parse failure, err.type === 'entity.parse.failed'.
app.use(function (error, req, res, next) {
if (error.type === 'entity.parse.failed') {
sendError(res, myCustomErrorMessage);
} else {
next();
}
});
I found checking for SyntaxError to be not enough, therefore I do:
if (err instanceof SyntaxError &&
err.status >= 400 && err.status < 500 &&
err.message.indexOf('JSON') !== -1) {
// process filtered exception here
}
create new module "hook-body-parser.js"
hook everything with body parser over here
const bodyParser = require("body-parser");
module.exports = () => {
return [
(req, res, next) => {
bodyParser.json()(req, res, (error) => {
if (error instanceof SyntaxError) {
res.sendStatus(400);
} else {
next();
}
});
},
bodyParser.urlencoded({ extended: true }),
];
};
and use over express like this
...
app.use(hookBodyParser())
...
if you want to catch all errors thrown by body-parsr for example
entity.too.large or encoding.unsupported
just place this middleware right after your body-parser initialization
$ npm i express-body-parser-error-handler
https://www.npmjs.com/package/express-body-parser-error-handler
for example:
const bodyParserErrorHandler = require('express-body-parser-error-handler')
const { urlencoded, json } = require('body-parser')
const express = require('express')
const app = express();
router.route('/').get(function (req, res) {
return res.json({message:"🚀"});
});
// body parser initilization
app.use('/', json({limit: '250'}));
// body parser error handler
app.use(bodyParserErrorHandler());
app.use(router);
...
(bodyParser, req, res) => new Promise((resolve, reject) => {
try {
bodyParser(req, res, err => {
if (err instanceof Error) {
reject(err);
} else {
resolve();
}
});
} catch (e) {
reject(e);
}
})
Bullet-proof. Future-aware. WTFPL-Licensed. And also useful w/ async/await.