Error: Can't set headers after they are sent. node.js - javascript

I'm tring to coed an application which lets users execute commands over url but I get this error message:
_http_outgoing.js:346
throw new Error('Can\'t set headers after they are sent.');
^Error: Can't set headers after they are sent.
at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:346:11)
at ServerResponse.header (C:\Users\Jarvis\node_modules\express\lib\response.js:718:10)
at ServerResponse.json (C:\Users\Jarvis\node_modules\express\lib\response.js:246:10)
at C:\Users\Jarvis\Desktop\sys.js:9:6
at ChildProcess.exithandler (child_process.js:193:7)
at emitTwo (events.js:100:13)
at ChildProcess.emit (events.js:185:7)
at maybeClose (internal/child_process.js:850:16)
at Process.ChildProcess._handle.onexit (internal/child_process.js:215:5)
This is my Code:
var Express = require('express');
var app = Express();
var sys = require('sys');
var exec = require('child_process').exec;
var child;
app.get("/:cmd", function(req, res) {
child = exec(req.params.cmd, function (error, stdout, stderr) {
res.json({"stdout":stdout});
res.json({"stderr": stderr});
if (error != null) {
console.log("exec error: "+error);
}
});
});
app.listen(8080);

You can only call res.json one time per http request.
change
res.json({"stdout":stdout});
res.json({"stderr": stderr});
to:
res.json({"stdout":stdout, "stderr": stderr});

Related

Https request Post from an Angular App to ExpressJS Node.js Server results in request write() end() is not a function and socket hang up Error

I am trying to invoke an Authorization Token API to get an access token.
The trigger is from an angular application via a button click.
The angular service code is below:
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { User } from './../auth/user';
import { AuthResponse } from './../auth/auth-response';
import { tap } from 'rxjs/operators';
import { Observable, BehaviorSubject } from 'rxjs';
#Injectable({
providedIn: 'root'
})
export class AuthService {
AUTH_SERVER = "http://localhost:3000";
authSubject = new BehaviorSubject(false);
constructor(private httpClient: HttpClient) { }
register(user: User): Observable<AuthResponse> {
return this.httpClient.post<AuthResponse>(`${this.AUTH_SERVER}/register`, user).pipe(
tap((res: AuthResponse ) => {
if (res.token) {
console.log("ACCESS_TOKEN : "+ res.token.access_token);
localStorage.set("ACCESS_TOKEN", res.token.access_token);
localStorage.set("EXPIRES_IN", res.token.token_type);
localStorage.set("ACCESS_TOKEN", res.token.expires_in);
localStorage.set("EXPIRES_IN", res.token.refresh_token);
this.authSubject.next(true);
}
})
);
}
}
And the NodeJS Backend service code is below:
const express = require('express')
const https = require('https')
const app = express()
const router = express.Router();
const cors = require('cors');
const bodyParser = require("body-parser")
const api_helper = require('./util/api_helper')
const port = 3000
app.use(cors());
router.use(bodyParser.urlencoded({ extended: false }));
router.use(bodyParser.json());
router.get('/', (req, res) => {
res.status(200).send('Welcome to Make REST API Calls to Authorisation Server In Express!');
});
router.post('/register', (req, res) => {
console.log('nodejs user name = '+req.body.username);
console.log('nodejs password = '+req.body.password);
var client_id = 'xxxx';
var client_secret = 'yyyyyy';
var auth_header = 'Basic ' + Buffer.from(client_id + ':' + client_secret).toString('base64');
const data = "grant_type=password&username=ddddd&password=eeeeee&client_id=fff&client_secret=Joe75";
const options = {
hostname: 'linux-2222',
port: 8543,
path: '/xxxx/oauth2/token',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-formurlencoded',
'Content-Length': data.length
}
};
const requestVar = https.request(options, (res) => {
console.log(`statusCode: ${res.statusCode}`)
res.on('data', (chunk) => {
console.log(`BODY: ${chunk}`);
});
res.on('end', () => {
console.log('No more data in response.');
});
});
requestVar.write(data);
requestVar.end();
req.on('error', (error) => {
console.log('error is ' + error);
});
});
app.use(router);
app.listen(port, () => console.log(`Node server listening on port ${port}!`))
The error I am getting is below:
Entering the server endpoint
nodejs user name = xxx
nodejs password = yyyy
(node:6285) Warning: Setting the NODE_TLS_REJECT_UNAUTHORIZED environment variable to '0' makes TLS connections and HTTPS requests insecure by disabling certificate verification.
**TypeError: req.write is not a function**
at /Users/admin/Development/mod/integrator/src/app/app.js:78:7
at invokeCallback (/Users/admin/Development/mod/integrator/node_modules/raw-body/index.js:224:16)
events.js:288
throw er; // Unhandled 'error' event
^
Error: socket hang up
at connResetException (internal/errors.js:604:14)
at TLSSocket.socketOnEnd (_http_client.js:460:23)
at TLSSocket.emit (events.js:323:22)
at endReadableNT (_stream_readable.js:1204:12)
at processTicksAndRejections (internal/process/task_queues.js:84:21)
Emitted 'error' event on ClientRequest instance at:
at TLSSocket.socketOnEnd (_http_client.js:460:9)
at TLSSocket.emit (events.js:323:22)
at endReadableNT (_stream_readable.js:1204:12)
at processTicksAndRejections (internal/process/task_queues.js:84:21) {
code: 'ECONNRESET'
}
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! integrator#0.0.1 start: `NODE_TLS_REJECT_UNAUTHORIZED='0' node ./src/app/contractor_lifecycle_app.js`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the integrator#0.0.1 start script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
npm ERR! A complete log of this run can be found in:
npm ERR! /Users/admin/.npm/_logs/2020-03-28T11_37_38_559Z-debug.log
The nodejs console shows errors with :
TypeError: req.write is not a function and Error: socket hang up.
FYI, I am getting the access token in postname using the relevant http request options. And I was able to use the access token to get a protected resource in postman.
But, I cannot even consume the authorization endpoint via nodejs express.
Please, I need someone to help, any ideas will do.
It appears the problem is with the https.request logic, but I dont know exactly where.
NOTE: The request parameter from the angular app is being successfuly logged in the console in the nodejs https request post function.
The req in the following line:
router.post('/register', (req, res) => {
was overriding the following:
req.write(data);
req.end();
The request write() and end() are methods of the object returned from https.request(options, (res) => {
So, I have updated the code by assigning the https.request(options, (res) => { .. to a new varibale called requestVar.
And now I am getting my acccess token from the authorization server.
I have updated original post with the fix.
Hurray.

Express route test with Supertest and Mocha failing

I have a set of tests to verify that my Express serves routes properly. For one of my routes launch.js, I receive two different errors, and sometimes the test randomly passes with long (425ms+) response times. Is there a better way to approach this?
launch.js
const authUtils = require('../../lib/authUtils');
const express = require('express');
const VError = require('verror');
const router = express.Router();
router.get('/', (req, res) => {
/**
* Request conformance object
*/
authUtils.getConformance((error, response, body) => {
// If error with HTTP request
if (error) {
throw new VError('Conformance object request failed', error);
// If error from auth server
} else if (response.body.message) {
throw new VError('Conformance object request failed', response.body.message);
// If request for conformance object succeeds
} else {
// Parse conformance object for tokenUri and authUri
authUtils.parseConformanceUris(body, (authUri, tokenUri, parsingError) => {
// Ensure URIs can be parsed from response
if (error) {
throw new VError('Issue while parsing conformance object', parsingError);
} else {
/**
* Data values needed later for /redirect
* #type {{state: string, tokenUri: string}}
*/
const launchData = {
state: authUtils.getUniqueCode(),
tokenUri,
};
// Build URI to request token from auth server
authUtils.buildGetTokenUri(authUri, launchData.state, (getTokenUri) => {
// Store state and tokenUri to session and redirect browser
authUtils.storeLaunchData(req, res, launchData, getTokenUri);
});
}
});
}
});
});
module.exports = router;
index.spec.js
const request = require('supertest');
const app = require('../index');
describe('Express server routes', () => {
describe('GET /launch', () => {
it('responds with HTTP 302', (done) => {
request(app).get('/launch').expect(302, done);
});
});
});
subject.getConformance
/**
* Utility function to request conformance object from auth server
* #param callback
*/
const getConformance = (callback) => {
request({ url: process.env.CONFORMANCE_URI, json: true, method: 'get' }, (error, response, body) => {
if (!error && response.statusCode === 200) {
callback(null, response, body);
} else {
callback(error, response, null);
}
});
};
Error 1
Uncaught TypeError: Cannot read property 'message' of null
at subject.getConformance (test/authUtils.spec.js:28:27)
at Request.request [as _callback] (lib/authUtils.js:7:374)
at Request.self.callback (node_modules/request/request.js:186:22)
at Request. (node_modules/request/request.js:1163:10)
at IncomingMessage. (node_modules/request/request.js:1085:12)
at endReadableNT (_stream_readable.js:1059:12)
at _combinedTickCallback (internal/process/next_tick.js:138:11)
at process._tickCallback (internal/process/next_tick.js:180:9)
Error 2
Uncaught AssertionError: expected 'body' to equal undefined
at subject.getConformance (test/authUtils.spec.js:43:16)
at Request.request [as _callback] (lib/authUtils.js:7:374)
at Request.self.callback (node_modules/request/request.js:186:22)
at Request. (node_modules/request/request.js:1163:10)
at IncomingMessage. (node_modules/request/request.js:1085:12)
at endReadableNT (_stream_readable.js:1059:12)
at _combinedTickCallback (internal/process/next_tick.js:138:11)
at process._tickCallback (internal/process/next_tick.js:180:9)
Assuming that the app object is requiring from a expressjs server, try
.get('/launch')
.expect(302)
.end(function (err, res) {
res.status.should.be.equal(302);
done();
});
If your index.js file is not a server then you need to configure the app object from a valid server. Are you exporting the app from index.js where app is
var express = require("express")
, app = express();
?

Socket.IO adapter throws uncatchable Timed Out error on MongoDB disconnection

I'm trying to catch mongodb disconnection event.
It works fine with the following setup:
simple.js
'use strict';
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost:27017/pnsockets', function () {
console.log('mongoose connected');
});
mongoose.connection.on('disconnected', function () {
console.log('mongoose disconnected');
});
If simple.js is running and I stop mongodb (launchctl stop homebrew.mxcl.mongodb), I get mongoose disconnected on the console, and I can handle the issue.
But running extended.js that is usung socket.io-adapter-mongo, when I kill mongodb, I get the following error:
/project/node_modules/mongoose/node_modules/mongodb/lib/utils.js:98
process.nextTick(function() { throw err; });
^
MongoError: server localhost:27017 timed out
at null.<anonymous> (/project/node_modules/mongodb-core/lib/topologies/server.js:436:40)
at emitTwo (events.js:87:13)
at emit (events.js:172:7)
at null.<anonymous> (/project/node_modules/mongodb-core/lib/connection/pool.js:144:10)
at g (events.js:260:16)
at emitTwo (events.js:87:13)
at emit (events.js:172:7)
at Socket.<anonymous> (/project/node_modules/mongodb-core/lib/connection/connection.js:172:12)
at Socket.g (events.js:260:16)
at emitOne (events.js:77:13)
at Socket.emit (events.js:169:7)
at TCP._onclose (net.js:468:12)
extended.js
'use strict';
var mongoose = require('mongoose');
var socketIO = require('socket.io');
var MongoAdapter = require('socket.io-adapter-mongo');
mongoose.connect('mongodb://localhost:27017/pnsockets', function () {
console.log('mongoose connected');
_setupSocketAdapter();
});
mongoose.connection.on('disconnected', function () {
console.log('mongoose disconnected');
});
var _setupSocketAdapter = function () {
var io = socketIO();
var socket = mongoose.connections[0].db;
socket.connection = mongoose.connections[0]; // mubsub will need this line
var mongoAdapter = MongoAdapter({socket: socket});
io.adapter(mongoAdapter);
};
How can I catch the MongoError: server localhost:27017 timed out error?
The problem is coming from socket.io-adapter-mongo itself.
If you take a look at the source code, they're using mubsub. Mubsub is basically a pub / sub implementation for Node.js and MongoDB.
They're setting up a client and a channel which is mapping one-to-one with a capped collection but there is no event handler attached on these parts.
According to the mubsub documentation, the following event are available on a channel: *, message, document, ready and error. The error event is also available on the client.
For example, simply adding the following code would catch the errors you're having.
channel.on('error', function (err) {
console.error(err.message);
});
client.on('error', function (err) {
console.error(err.message);
});
In case of a disconnection, you'll get the following output instead of the unhandled error.
mongoose connected
server localhost:27017 timed out
mongoose disconnected
Mubsub: broken cursor.

Node JS error "getaddrinfo ENOTFOUND"

I'm having trouble in accessing MYSQL.
There is a GET METHOD at my code below :
app.get('/users',function(request,response){
client.query('select * from User where 1=1',function(error,result){
if(error){
response.json('unfortunately fail');
console.log('unfortunately fail , error : %s',error);
console.log('error stack: %s',error.stack);
console.log('error message: %s',error.message);
throw error;
}else{
console.log('select success....');
response.json('select success....');
response.json(result);
}
});
});
When that method is executed, there is an error :
unfortunately fail , error : Error: getaddrinfo ENOTFOUND
error stack: Error: getaddrinfo ENOTFOUND
at errnoException (dns.js:37:11)
at Object.onanswer [as oncomplete] (dns.js:124:16)
at Protocol._enqueue (/node_modules/mysql/lib/protocol/Protocol.js:135:48)
at Protocol.handshake (/node_modules/mysql/lib/protocol/Protocol.js:52:41)
at Connection.connect (/node_modules/mysql/lib/Connection.js:123:18)
at Connection._implyConnect (/node_modules/mysql/lib/Connection.js:417:10)
at Connection.query (/node_modules/mysql/lib/Connection.js:199:8)
at app.listen.host (/web.js:70:10)
at callbacks (/node_modules/express/lib/router/index.js:164:37)
at param (/node_modules/express/lib/router/index.js:138:11)
at pass (/node_modules/express/lib/router/index.js:145:5)
at Router._dispatch (/node_modules/express/lib/router/index.js:173:5)
And this is about the variables (express, mysql ...)
var http = require('http');
var express = require('express');
var request = require('request');
var mysql = require('mysql');
var client = mysql.createConnection({
host:'http://nodejs.somewhere.com/WebMysql',
port : 3306,
user : 'user',
password : 'password',
database : 'database'
});
var app = express();
app.use(express.bodyParser());
app.use(app.router);
Your host setting for your mysql database connection is incorrect (ENOTFOUND for getaddrinfo means DNS resolution failed). It needs to be just the hostname of the mysql server (e.g. nodejs.somewhere.com).

Error: Can't set headers after they are sent. RabbitMQ interfering with NodeJS response

After a http response, I am sending a messing using RabbitMQ (creating a channel etc) and however, the server is complaining that "Error: Can't set headers after they are sent."
Here is the code:
var amqp = require('amqplib');
var when = require('when');
var rabbitmq_conn = amqp.connect('amqp://localhost' );
function push_keystroke_data(session_id, data) {
var QUEUE_NAME = 'hello';
var msg = session_id;
when(rabbitmq_conn.createChannel()).then(function(ch) {
var ok = ch.assertQueue(QUEUE_NAME, {durable: false});
ok.then(function(_qok) {
ch.sendToQueue(QUEUE_NAME, new Buffer(msg));
console.log(" [x] Sent '%s'", msg);
ch.close();
});
}).ensure(function() {
conn.close();
});
}
router.post('/', function(req, res, next) {
// current session id
var sid;
if (req.cookies.papi) {
sid = req.cookies.papi.session_id;
} else {
sid = generate_session_id();
res.cookie('papi', {session_id: sid}, {maxAge: COOKIE_MAX_AGE});
}
res.send(JSON.stringify({ user_id: get_user_id(sid)}));
var data = process_keystroke_data(req.body);
push_keystroke_data(sid, data);
});
I assuming RabbitMQ is setting the headers after the response (I have also tried sending the RabbitMQ message before the response but that also didn't solve anything).
Here is the stack trace:
POST /api 500 220.100 ms - 16
Error: Can't set headers after they are sent.
at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:335:11)
at ServerResponse.header (/Users/mikeecb/Documents/KeyNA/jsbackend/node_modules/express/lib/response.js:700:10)
at ServerResponse.send (/Users/mikeecb/Documents/KeyNA/jsbackend/node_modules/express/lib/response.js:154:12)
at fn (/Users/mikeecb/Documents/KeyNA/jsbackend/node_modules/express/lib/response.js:934:10)
at View.exports.renderFile [as engine] (/Users/mikeecb/Documents/KeyNA/jsbackend/node_modules/jade/lib/index.js:374:12)
at View.render (/Users/mikeecb/Documents/KeyNA/jsbackend/node_modules/express/lib/view.js:93:8)
at EventEmitter.app.render (/Users/mikeecb/Documents/KeyNA/jsbackend/node_modules/express/lib/application.js:566:10)
at ServerResponse.res.render (/Users/mikeecb/Documents/KeyNA/jsbackend/node_modules/express/lib/response.js:938:7)
at /Users/mikeecb/Documents/KeyNA/jsbackend/app.js:62:7
at Layer.handle_error (/Users/mikeecb/Documents/KeyNA/jsbackend/node_modules/express/lib/router/layer.js:58:5)
Any solutions or ideas would be much appreciated.
It turns out that the issue was not that RabbitMQ was setting the headers (which would be weird, why would it be doing any http stuff?) but that after responding res.send(JSON.stringify({ user_id: get_user_id(sid)}));, I tried to send another respond which obviously the issue.

Categories