Express can't set headers after they are sent to the client - express

I have the following code:
router.post('/:email/addWorkflow', async function (req, res, next) {
const params = req.params;
const workflow = req.body;
const email = params.email;
User.findOne({ email: email }, function (err, user) {
if (err) {
res.status(500).send({
error: 'Error while querying database'
});
} else if (user) {
const workflows = user.workflows;
workflows.forEach(wf => {
if (wf) {
if (wf.workflowId === workflow.workflowId) {
res.status(409).send({
error: 'Workflow with that id already exists'
});
}
}
});
workflows.push(workflow);
User.updateOne({ email: email }, { $set: { workflows: workflows } }, { upsert: false }, function (err) {
if (err) {
res.status(500).send({
message: 'Error while updating database'
});
} else {
res.status(200).send({
message: 'Wf added successfully'
});
}
});
} else {
res.status(404).send({
message: 'No such user'
});
}
});
});
After I make a post with an already existing workflowId, I get the following error:
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at ServerResponse.setHeader (_http_outgoing.js:485:11)
..........
at /home/petar/Documents/jsProjects/p/backend/routes/users.js:50:29
at CoreDocumentArray.forEach (<anonymous>)
at /home/petar/Documents/jsProjects/p/backend/routes/users.js:47:17
at /home/petar/Documents/jsProjects/p/backend/node_modules/mongoose/lib/model.js:4915:16
at /home/petar/Documents/jsProjects/p/backend/node_modules/mongoose/lib/model.js:4915:16
at /home/petar/Documents/jsProjects/linear-mixed-models/backend/node_modules/mongoose/lib/query.js:4380:11
[... lines matching original stack trace ...]
at processTicksAndRejections (internal/process/task_queues.js:76:11) {
code: 'ERR_HTTP_HEADERS_SENT'
Any ideas? I looked at other posts for the same error. I understand that it happens if I try to send response 2 time: res.send({...}) and res.send({...}). However, this does not happen in my case. Thanks in advance

I am not completely sure what line the error message is indicating, but the following loop is the only place I can think of a multiple response on your code
workflows.forEach(wf => {
//foreach is looping
if (wf) {
if (wf.workflowId === workflow.workflowId) {
res.status(409).send({
error: 'Workflow with that id already exists'
});
//but I don't think this guy will stop looping after the first "send()"
}
}
});

Related

How to protect routes using JWT in NextJS?

I was working on a project in next js where i need to protect some routes. I was trying to do this using jwt but for some reason it's not working, the POST method below inside index.js is injecting new entry in db bypass the verify token middleware. Any kind of help would be greatly appreciated.
verifyAuthToken.middleware.js
import jwt from "jsonwebtoken";
export default function verifyAuthToken(req, res) {
try {
const token = req.headers;
if (!token) {
return res.status(401).json({
success: false,
msg: "You are not authorized to access this route",
});
}
const { userId } = jwt.verify(
req.headers.authorization,
process.env.TOKEN_SECRET
);
if (!userId) {
return res.status(401).json({
success: false,
msg: "You are not authorized to access this route",
});
}
req.userId = userId;
} catch (error) {
res.status(401).json({
success: false,
msg: "You are not authorized to access this route",
error: error.message,
});
}
}
index.js
import verifyAuthToken from "../../../middleware/verifyAuthToken.middleware";
import Evoluter from "../../../models/Evoluter.model";
import dbConnect from "../../../server-utils/connectDB";
import { sendEmail } from "../../../server-utils/sendEmail";
import baseURL from "../../../utils/baseURL";
export default async (req, res) => {
const { method } = req;
verifyAuthToken(req, res);
await dbConnect();
switch (method) {
// #route GET api/evoluters
// #desc Create new evoluter
// #access Private
case "POST":
try {
const { name, email } = req.body;
const evoluter = await Evoluter.findOne({ email: email.toLowerCase() });
if (evoluter) {
return res.status(400).json({
success: false,
msg: "Evoluter already exists",
});
}
const newEvoluter = await Evoluter.create({
name,
email: email.toLowerCase(),
});
try {
await sendEmail({
email: newEvoluter.email,
subject: "Welcome to Rubrica",
message: `Hi ${newEvoluter.name}, welcome to Rubrica. Please click on the link below to activate your account. ${baseURL}/home/${newEvoluter._id}`,
});
res.status(201).json({
success: true,
data: newEvoluter,
msg: "Evoluter created successfully. Please check your email to activate your account.",
});
} catch (error) {
console.log(error);
res.status(500).json({
success: false,
msg: "Error sending invitation email, please let the admin know.",
});
}
} catch (error) {
res.status(400).json({
success: false,
msg: "Sorry, we couldn't send the invitation. Please try again.",
error: error,
});
}
break;
default:
res.status(400).json({
success: false,
msg: "Invalid request",
});
break;
}
};
Here we can see that the verify token middleware was fired as expected, however the data inside the body got injected into the DB which we don't really need.
Postman output
Please let me know if you need more information I don't have much experience asking questions in stackoverflow.
It is bypassing the verifyAuthToken function because You are doing it anyway you are just generating response on verifyAuthToken
You can return a boolean at the end of your verifyAuthToken something like this:
if (userId) return true;
else return false;
Then in your index.js before injecting data to database instead of verifyAuthToken(req, res); do this:
if (!verifyAuthToken(req, res)) {
return;
}
You can also use NextJs middleware

Nuxt: Import a js depending on i18n

I am currently importing a js file and processing it right with the folowwing asyncdata
async asyncData({ route, error }) {
try {
const entry = await import(
`~/assets/data/portafolio/${route.params.work}.js`)
return { entry: entry.default || entry }
} catch (error_) {
error({
message: 'Not Found',
statusCode: 404,
})
}
return {}
},
But when I try to add a language identifier to load the right file, that doesnt work.
async asyncData({ route, error }) {
try {
const entry = await import(
`~/assets/data/${this.i18n.locale}/portafolio/${route.params.work}.js`)
return { entry: entry.default || entry }
} catch (error_) {
error({
message: 'Not Found',
statusCode: 404,
})
}
return {}
},
Of course the path and files exists but I am getting an error with:
http://localhost:3000/[object%20Object],[object%20Object],[object%20Object],[object%20Object],[object%20Object],[object%20Object] 404 (Not Found)
Any ideas on whats going wrong?
Thank you in advance!
I have found a solutiond and it is simple.
I was missing to add the app and then using it inside asuncData (on that context this. doesnt do anything)
async asyncData({ route, app, error }) {
try {
const entry = await import(
`~/assets/data/${app.i18n.locale}/portafolio/${route.params.work}.js`)
return { entry: entry.default || entry }
} catch (error_) {
error({
message: 'Not Found',
statusCode: 404,
})
}
return {}
},

Unhandled promise rejection: Error: Request failed with status code 500

I am trying to call an api and I get the error "Unhandled promise rejection: Error: Request failed with status code 500". I dunno how did I get the error.I put the api call in componentDidMount. I am not sure whether the error comes from the redux implementation or from how I called the api.
This is how I called the api. After a successful login, I put the username as a token and use it to call another api.
state={
username: '',
semcode: [
{}
]
}
componentWillMount() {
AsyncStorage.getItem('Login_token').then((token) => {
console.log('this is coursescreen',token);
let Login_token = token;
this.setState({ username: Login_token });
});
}
componentDidMount(){
this.props.getSemcode(this.state.username);
}
componentWillReceiveProps(nextProps) {
console.log('xx',nextProps);
if (nextProps.semCode != undefined) {
this.setState({ semcode: nextProps.semCode });
}
}
This is how I wrote my action file:
export const getSemcode = (username) => async dispatch => {
let param = {
nomatrik: username,
}
console.log(`${helper.ROOT_URL}/result/GetListOfKodSesiSem`)
let code_res = await
axios.post(`${helper.ROOT_URL}/result/GetListOfKodSesiSem`, param)
console.log(code_res.data);
if (code_res.data.length > 0) {
const { code } = code_res.data;
dispatch({ type: SEMCODE_FETCH_SUCCESS, payload: { semCode: code }});
}
}
This is how I wrote my reducer:
import { SEMCODE_FETCH_SUCCESS} from '../actions/types';
const INITIAL_STATE={
semCode:[],
}
export default function (state=INITIAL_STATE, action){
switch(action.type){
case SEMCODE_FETCH_SUCCESS:
return action.payload
default:
return state;
}
}
Can anyone help me pleaseeeeee
Error Message
Error received from axios.post: {"config":{"transformRequest":
{},"transformResponse":{},"timeout":0,"xsrfCookieName":"XSRF-
TOKEN","xsrfHeaderName":"X-XSRF-TOKEN","maxContentLength":-1,"headers":
{"Accept":"application/json, text/plain, /","Content-
Type":"application/json;charset=utf-8"},
"method":"post","nomatrik":"BB16160907",
"url":"https://smp.ums.edu.my/api/result/GetListOfKodSesiSem","data":"
{\"Accept\":\"application/json\",\"Content-
Type\":\"application/json\"}"},"request":
{"UNSENT":0,"OPENED":1,"HEADERS_RECEIVED":2,"LOADING":3,"DONE":4,
"readyState":4,"status":500,"timeout":0,"withCredentials":true,"upload":
{},"_aborted":false,"_hasError":false,"_method":"POST","_response":"
{\"Message\":\"An error has occurred.\"}",
"_url":"https://smp.ums.edu.my/api/result/GetListOfKodSesiSem",
"_timedOut":false,"_trackingName":"unknown",
"_incrementalEvents":false,"responseHeaders":{"Date":"Sat, 30 Dec 2017
03:58:25
GMT","Content-Length":"36","X-Powered-By":"ARR/3.0","X-AspNet-
Version":"4.0.30319","Expires":"-1","Content-Type":"application/json;
charset=utf-8","Server":"Microsoft-IIS/10.0","Pragma":"no-cache","Cache-
Control":"no-cache"},"_requestId":null,"_headers":
{"accept":"application/json, text/plain, /","content-
type":"application/json;charset=utf-
8"},"_responseType":"","_sent":true,"_lowerCaseResponseHeaders":{"date":"Sat,
30 Dec 2017 03:58:25
GMT","content-length":"36","x-powered-by":"ARR/3.0","x-
aspnet-version":"4.0.30319","expires":"-1","content-type":"application/json; charset=utf-8","server":"Microsoft-IIS/10.0","pragma":"no-cache","cache-
control":"no-cache"},"_subscriptions":[],"responseURL":
"https://smp.ums.edu.my/api/result/GetListOfKodSesiSem"},"response":{"data":
{"Message":"An error has
occurred."},"status":500,"headers":{"date":"Sat, 30 Dec 2017 03:58:25
GMT","content-length":"36","x-powered-by":"ARR/3.0","x-
aspnet-version":"4.0.30319","expires":"-1","content-type":"application/json; charset=utf-8","server":"Microsoft-IIS/10.0","pragma":"no-cache","cache-
control":"no-cache"},"config":{"transformRequest":{},"transformResponse":
{},"timeout":0,"xsrfCookieName":"XSRF-TOKEN","xsrfHeaderName":"X-XSRF-
TOKEN","maxContentLength":-1,"headers":{"Accept":"application/json,
text/plain,
/","Content-Type":"application/json;charset=utf-8"},"method": "post","nomatrik":"BB16160907",
"url":"https://smp.ums.edu.my/api/result/GetListOfKodSesiSem","data":"
{\"Accept\":\"application/json\",\"Content-
Type\":\"application/json\"}"},"request":
{"UNSENT":0,"OPENED":1,"HEADERS_RECEIVED":2,"LOADING":3,"DONE":4,
"readyState":4,"status":500,"timeout":0,"withCredentials":true,"upload":
{},"_aborted":false,"_hasError":false,"_method":"POST","_response":"
{\"Message\":\"An error has occurred.\"}",
"_url":"https://smp.ums.edu.my/api/result/GetListOfKodSesiSem",
"_timedOut":false,"_trackingName":"unknown","_incrementalEvents":false, "responseHeaders":{"Date":"Sat, 30 Dec 2017 03:58:25 GMT","Content-
Length":"36","X-Powered-By":"ARR/3.0","X-AspNet-
Version":"4.0.30319","Expires":"-1","Content-Type":"application/json;
charset=utf-8","Server":"Microsoft-IIS/10.0","Pragma":"no-cache","Cache-
Control":"no-cache"},"_requestId":null,"_headers":
{"accept":"application/json, text/plain, /","content-
type":"application/json;charset=utf-
8"},"_responseType":"","_sent":true,"_lowerCaseResponseHeaders":{"date":"Sat,
30 Dec 2017 03:58:25
GMT","content-length":"36","x-powered-by":"ARR/3.0","x-
aspnet-version":"4.0.30319","expires":"-1","content-type":"application/json; charset=utf-8","server":"Microsoft-IIS/10.0","pragma":"no-cache","cache-
control":"no-cache"},"_subscriptions":
[],"responseURL":"https://smp.ums.edu.my/api/result/GetListOfKodSesiSem"}}}
Login action:
export const attemptLogin = (username, password) => async dispatch => {
let param = {
txtNomatrik: username,
txtPwd: password,
public_key: helper.PUBLIC_KEY,
secret_key: helper.SECRET_KEY
}
console.log(`${helper.ROOT_API_URL}/v1/basic/ad/std/login`)
let login_res = await
axios.post(`${helper.ROOT_API_URL}/v1/basic/ad/std/login`, param)
console.log(login_res.data);
await AsyncStorage.setItem('jwtToken',login_res.data.token);
if (login_res.data.status == 'Successful login') {
const { login } = login_res.data;
dispatch({ type: LOGIN_SUCCESS});
}
}
Problem
Your request is failing because you are not adding the JWT token to the headers.
Solution
Using Axios and with your code this should work. Evidently our big problem here was that you have to pass data even though it is empty. If we do not pass data it fails with error 500.
export const getSemcode = (username) => async dispatch => {
let jwtToken = await AsyncStorage.getItem('jwtToken').then((data) => {
console.log('this is semcode',data);
});
let config = {
method: 'POST',
url: 'url/to/sem',
headers: {
'content-type': 'application/x-www-form-urlencoded',
AntiTemperSignature: jwtToken,
UserID: '123456',
},
data: '',
json: true
};
try {
return axios(config)
.then((response) => {
console.log(response);
if (response.data.length > 0) {
const { code } = response.data;
dispatch({ type: SEMCODE_FETCH_SUCCESS, payload: { semCode: code } });
}
})
.catch((error) => {
console.log(error);
});
}
}
You are looking in the wrong place.
An error code 500 is returned by the remote server when it can't handle the request. In this case, I suspect that the POST to ${helper.ROOT_URL}/result/GetListOfKodSesiSem is failing. The axios library is a promise based library. Wrap the call in a try-catch block like this:
try {
console.log(`${helper.ROOT_URL}/result/GetListOfKodSesiSem`)
let code_res = await
axios.post(`${helper.ROOT_URL}/result/GetListOfKodSesiSem`, param)
console.log(code_res.data);
if (code_res.data.length > 0) {
const { code } = code_res.data;
dispatch({ type: SEMCODE_FETCH_SUCCESS, payload: { semCode: code }});
}
} catch (err) {
console.error(`Error received from axios.post: ${JSON.stringify(err)}`);
}
This will at least give you a view in your debug console on what is happening. You can then coordinate that call with any debug logs from the backend to figure out what the error really is.
Your root cause, however, is that the remote server is returning a Server Error (HTTP code 500) to your client.

Using async in express

Below is my rest API endpoint /signup. The problem I'm having now is that the endpoint does not stop after validateEmail. Even after it failed email form-validation and res.send() is done, the endpoint continues. So I'm keep getting the error 'Error: Can't set headers after they are sent.'. I would like to be able to finish the endpoint inside its functions like validateEmail , checkEmailInUse, makeUser, and so on.
router.post("/signup", async (req, res, next) => {
const { email, password } = req.body;
const users = req.app.get("users");
validateEmail(res, email);
await checkEmailInUse(res, users, email);
const user = await makeUser(res, users, email, password);
res.send({ message: "POST signup request OK", user });
});
function validateEmail(res, email) {
const isEmail = emailFilter.test(email);
if (!isEmail) {
res.status(400).send({
error: {
message: "Requested email is not email type",
type: "FormatValidation",
location: "validateEmail"
}
});
return;
}
}
async function checkEmailInUse(res, users, email) {
const query = { email };
try {
const user = await users.findOne(query);
if (user) {
res.send({ message: "The email is already used" });
}
} catch (err) {
res.status(400).send({
error: {
message: "Failed to find user",
type: "DatabaseError",
location: "checkEmailInUse"
}
});
return;
}
}
The code keeps going after a failed validate because you call:
validateEmail(res, email);
and then your code just keeps going. This is normal flow of control in Javascript. Your function keeps executing lines of code until you return in the function. The same issue is true for checkEmailInUse(). If you want to sometimes send the response inside those functions and be done, then you need a return value from those functions that you can check and then use if statements to determine whether your code should do more or not.
Following your style of sending the error response inside the validation functions (which is not how I would probably structure things), you could return values from those functions and test those return values in the request handler like this:
router.post("/signup", async (req, res, next) => {
const { email, password } = req.body;
const users = req.app.get("users");
if (validateEmail(res, email)) {
if (await checkEmailInUse(res, users, email)) {
const user = await makeUser(res, users, email, password);
res.send({ message: "POST signup request OK", user });
}
}
});
function validateEmail(res, email) {
const isEmail = emailFilter.test(email);
if (!isEmail) {
res.status(400).send({
error: {
message: "Requested email is not email type",
type: "FormatValidation",
location: "validateEmail"
}
});
return false;
}
return true;
}
async function checkEmailInUse(res, users, email) {
const query = { email };
try {
const user = await users.findOne(query);
if (user) {
res.send({ message: "The email is already used" });
return false;
} else {
return true;
}
} catch (err) {
res.status(400).send({
error: {
message: "Failed to find user",
type: "DatabaseError",
location: "checkEmailInUse"
}
});
return false;
}
}
}
But, I think you might find this is simpler if you get rid of the local functions because then when you send a response, you can just directly return from the main function and be done. Here's how that could look:
router.post("/signup", async (req, res, next) => {
function err(res, message, type, location) {
res.status(400).send({error: {message, type, location}});
}
const { email, password } = req.body;
if (!emailFilter.test(email)) {
err(res, "Requested email is not email type", "FormatValidation", "validateEmail");
return;
}
const users = req.app.get("users");
try {
const user = await users.findOne({email});
if (user) {
res.send({ message: "The email is already used" });
return;
}
} catch(e) {
err(res, "Failed to find user", "DatabaseError", "checkEmailInUse");
return;
}
try {
const user = await makeUser(res, users, email, password);
res.send({ message: "POST signup request OK", user });
} catch(e) {
err(res, "Failed to make user", "DatabaseError", "makeUser");
}
}

Node js: mssql [ConnectionError: Connection is closed.] name: 'ConnectionError', message: 'Connection is closed.', code: 'ECONNCLOSED'

i am getting error in npm mssql 3.0.0 with sqlserver 2012
i am creating single page application where i used restful using express .
there are 4 method which executing the query and returning the data to response.
for each method i am opening the connection and closing the connection.
but when savedquery is calling then connection close error occurs.
each method code is similar to savedquery method (copy pasted code only queries are changed) but they are executing savedquery is not executing
{ [ConnectionError: Connection is closed.]
name: 'ConnectionError',
message: 'Connection is closed.',
code: 'ECONNCLOSED' }
var savedquery=function(req,res){
dbConfig= {
user: 'XXX',
password: 'XXXXXXXXXX',
server: 'localhost', // You can use 'localhost\\instance' to connect to named instance
database: 'DEMO_ODS',
options: {
encrypt: true
}
};
sql.connect(dbConfig).then(function (err) {
var sqlrequest = new sql.Request();
sqlrequest.query("SELECT * from SavedQuery").then(function (recordset) {
sql.close(function (value) {
console.log("connection6 closed");
});
return res.status(200).send(recordset);
}).catch(function (err) {
console.log(err);
});
}).catch(function (err) {
console.log(err);
});
};
}
I know it is an old questionm but this answer is for the others who are facing the same isue. I had the same problem, What I did is, used promises as below.
function getData() {
try {
sqlInstance.connect(setUp)
.then(function () {
// Function to retrieve all the data - Start
new sqlInstance.Request()
.query("select * from Course")
.then(function (dbData) {
if (dbData == null || dbData.length === 0)
return;
console.dir('All the courses');
console.dir(dbData);
})
.catch(function (error) {
console.dir(error);
});
// Function to retrieve all the data - End
// To retrieve specicfic data - Start
var value = 1;
new sqlInstance.Request()
.input("param", sqlInstance.Int, value)
.query("select * from Course where CourseID = #param")
.then(function (dbData) {
if (dbData == null || dbData.length === 0)
return;
console.dir('Course with ID = 1');
console.dir(dbData);
})
.catch(function (error) {
console.dir(error);
});
// To retrieve specicfic data - End
}).catch(function (error) {
console.dir(error);
});
} catch (error) {
console.dir(error);
}
}
This solved my issue. You can find the fix here.
You should remove
options: {
encrypt: true
}
from your dbConfig
I just use promise to handle concurrent request:
const executeQuery = function (res, query, dbName) {
dbConfig = {
user: "********",
password: "********",
server: "*******",
database: dbName
}
sql.connect(dbConfig).then(pool => {
return pool.request().query(query)
}).then(result => {
res.send(result);
}).catch(err => {
res.send(err);
});
}
Hope it's help someone.