I am exploring node and express with redux where I want to set a cookie after the page has been rendered and wanna use the updated state for setting a cookie where I am getting this error.
Please help me in getting the answers of following ?
1) Let me know wheather the syntax I've written is correct or not and if not ,then what should be done?
2) How can i set a cookie to response after successful render of ejs file?
router.get('/dashboard',isLoggedIn,(req, res) => {
store.dispatch(initialize(reduxOauthConfig))
.then(() => match({ routes: dashroutes, location: req.url }, (error, redirectLocation, renderProps) => {
if (redirectLocation) {
res.redirect(301, redirectLocation.pathname + redirectLocation.search);
} else if (error) {
res.status(500).send(error.message);
} else if (!renderProps) {
res.status(404).send('Not found');
} else {
loadOnServer({ ...renderProps, store })
.then(() => {
const componentHTML = ReactDOMServer.renderToString(
<Provider store={store}>
<ReduxAsyncConnect {...renderProps}/>
</Provider>
);
const initialState = store.getState();
res.render('dashboard.ejs', {
markup: componentHTML,
intialState:initialState
});
})
.then(html => {
// !!! IMPORTANT TO PERSIST SESSION IF JavaScript failed to load / initialize
res.cookie('authHeaders', JSON.stringify(getHeaders(store.getState())), { maxAge: now() * 0.001 + 14 * 24 * 3600 });
res.end(html);
})
.catch(err => {
console.log(err.stack);
res.end(err.message);
});
}
}));
});
This error is caused by trying to send more of a response after the response has already been sent and finalized. This issue is often triggered in people's code by faulty async handling in request handlers.
In your promise chain, you are doing res.render(), then res.cookie(), then res.end(html).
res.render() all by itself sends the response. The following two commands are then trying to send a response when a response has already been sent, thus you get the error you are seeing.
Also, your second .then() handler after loadOnServer() appears to be expecting an argument you named html, but the previous .then() handler does not return anything so that html argument will be undefined.
It is not clear to me what you intend for the logic to be here since you seem to be trying to send rendered HTML twice in the same promise chain.
Related
here I try to run simple server using nodejs
server listen for massage to be posted to "/msg" then it write down the message to entry.txt and redirect user to "/home"
but It get error code: 'ERR_HTTP_HEADERS_SENT' and stop server while redirecting user witch result in display of This site can’t be reached page
import http from "http";
import fs from "fs";
export default sample_server()
function sample_server() {
const server = http.createServer((req ,res)=>{
const {url , method} = req;
res.setHeader("Content-Type", "text/html");
if(url === "/home"){
res.write("<html>")
res.write("<head><title>page</title></head>")
res.write("<body><center><h1>welcome</h1>")
res.write("<form method='POST' action='/msg'>")
res.write("<input type='text' name='msg'>")
res.write("<input type='submit'>")
res.write("</form></center></body></html>")
return res.end()
}else if(url === "/msg" && method ==="POST"){
res.write("<html>")
res.write("<head><title>page</title></head>")
res.write("<body><center><h1>massage</h1></center></body>")
res.write("</html>")
let msg = [];
req.on("data" , chunk => {
msg.push(chunk)
})
req.on("end" , () => {
msg = Buffer.concat(msg).toString().split("=")[1]
fs.appendFileSync("./files/entry.txt" , `entered: ${msg}\n`)
})
res.writeHead(302, { Location: "/home" })
return res.end()
}else{
res.write("<html>")
res.write("<head><title>page</title></head>")
res.write("<body><center><h1>not found</h1></center></body>")
res.write("</html>")
return res.end()
}
})
server.listen(3030)
}
I wonder if it got anything to do with req.on("data" , () => {...}) or req.on("end" , () => {...}) running async from respons
so far I tried using
res.statusCode = 302;
res.setHeader("Location", "/");
instead of res.writeHead(302, { Location: "/home" }); but I didn't solve the problem
You are trying to write the header AFTER you send the body, but the header needs to be sent before. When you call the first res.write(), that causes the http library to send the headers (with whatever has been set up to that point). When you then try to do res.writeHead(302, { Location: "/home" }) later, the http engine realizes that the headers have already sent and thus you get the error ERR_HTTP_HEADERS_SENT because that's literally what the http engine is discovering. You're asking to send headers, but they've already been sent. Obviously, you can't do things in that order.
There's also no point in sending a body to the request when you're sending a redirect (the browser won't display the body anyway so it's just a waste to send the body).
And, as I said in a comment, you should put the res.end() into the end event handler so you aren't ending the request until you're done reading the incoming stream.
And, you shouldn't be using synchronous I/O in your http server request handlers because that can ruin the ability of your server to scale. Instead, use asynchronous file I/O.
To fix all four of these, change from this:
res.write("<html>")
res.write("<head><title>page</title></head>")
res.write("<body><center><h1>massage</h1></center></body>")
res.write("</html>")
let msg = [];
req.on("data" , chunk => {
msg.push(chunk)
})
req.on("end" , () => {
msg = Buffer.concat(msg).toString().split("=")[1]
fs.appendFileSync("./files/entry.txt" , `entered: ${msg}\n`)
})
res.writeHead(302, { Location: "/home" })
return res.end()
to this:
res.writeHead(302, { Location: "/home" })
let msg = [];
req.on("data" , chunk => {
msg.push(chunk)
})
req.on("end" , () => {
msg = Buffer.concat(msg).toString().split("=")[1]
fs.appendFile("./files/entry.txt" , `entered: ${msg}\n`, (err) => {
if (err) {
console.log(err);
}
res.end();
});
});
This is a course quiz and this is the most basic information I need in order to create a React app. But while the endpoint URL is correct, the page "/products" returns a "400" error when I try to request the product list. The instructions I'm given are:
Obtain a list of products with
Route: /products
Body: Array
method: POST
{
"product-codes": [
"98798729",
"84876871",
"29879879",
]
}
My index.js
...
app.post(`/products`, async (req, res) => {
try {
const response = await axios.post(`${apiURL}/products`);
// console.log(response.data);
res.status(200).json(response.data);
} catch (error) {
res.status(400).json({ message: error.message });
}
});
in Postman
I use http://localhost:4000/products
and pass a Body / Raw /JSON:
{
"product-codes": [
"98798729",
"84876871",
"29879879",
]
}
But I can't get in! I am not seeing something obvious because this is the entry point to a very long and complex quiz. Thanks
What I see from the code is a recursive long call.
app.post(`/products`, async (req, res) => {
try {
const response = await axios.post(`${apiURL}/products`); // calling the same end point
// console.log(response.data);
res.status(200).json(response.data);
} catch (error) {
res.status(400).json({ message: error.message });
}
});
You should do something like this:
app.post(`/products`, async (req, res) => {
// do your logic
// when you pass body from postman on this endpoint
// you will receive the body here and save it to DB
// or do the manipulation and then send back the response
res.status(200).json(req.body.data);
});
I highly recommend you to first follow through some tutorials to understand how API works and how to create simple API using Node.js.
I am currently writing a route which allows me to recieve information from a stored procudre I have in a database. I have written a request in AngularJS and a route in NodeJS but I am just recieving a pending request in the chrome Network developer window. I can see that the console.log in the NodeJs app has the data I require so it has retrieved it but there is nothing coming back in any of the console logs in the the AngularJS app.
Here is the code for the both the angularJS app and the Node App:
AnglaurJS:
checkForReplenishmentEmptyTrolley = async () => {
LIBRIS.extensions.openLoadingModal();
console.log('in checkForReplenishmentEmptyTrolley');
try {
const varPromise = await $http.get(`${LIBRIS.config.stockService}stockMovement/checkForUnattachedTrolley`)
.then((response) => {
console.log(response);
// Request completed successfully
}, (error) => {
// Request error
console.log(error);
});
console.log(varPromise.data);
// 1. check that there are no ghost replenish - lines 1-15
console.log('in try/catch');
console.log('promise', varPromise);
} catch (error) {
console.log(error);
}
},
NodeJS code:
app.get(`${ROUTE}/attachTrolley`, async function(req, res){
const newRequest = await DB.newRequest();
console.log('we have made it to the route');
try {
console.log('we have made it to the Try/Catch route');
newRequest.input();
const record = await newRequest.execute('dbo.usp_STK_CheckForUnattachedTrolley');
res.json(record)
console.log(record, 'record');
} catch (err){
handleError(res, err);
console.log(err);
}
});
The problem is that you are doing a .then on a awaited promises and not returning anything from that. You have two choice here
Either return response from then so when you try to access the value here console.log(varPromise.data); it works.
Or remove the .then alltogather as it is not required because you are awaiting it any ways.
Basically just do this
checkForReplenishmentEmptyTrolley = async () => {
LIBRIS.extensions.openLoadingModal();
console.log("in checkForReplenishmentEmptyTrolley");
try {
const varPromise = await $http.get(`${LIBRIS.config.stockService}stockMovement/checkForUnattachedTrolley`);
console.log(varPromise.data);
// 1. check that there are no ghost replenish - lines 1-15
console.log("in try/catch");
console.log("promise", varPromise);
} catch (error) {
console.log(error);
}
};
Hope this fixes your issue.
Solved it! I had no return statement in my route!
I have an angular project back end with node.js, how can I call and get httpErrorResponse status or headers to display in my components page when my server is down or not responding.
here is my component function code:
UpdateData(){
this.newServices.updateNews(result, result.id).subscribe(
(res)=>{
console.log(res)
}),
(error)=>{
console.log(error)
}
}
my service.ts function:
updateNews(data, id) {
try {
return this.http.post(this.baseurl + "/news/update/" + id, data)
} catch (err) {
this.handleError(err);
}
}
how can I check in my component the http responses so that I can display messages on the browser
Generally its not advisable to show the error message to the user that returned from server. For example the error may be: Cant reach the xx.xx.xx due to CORS policy. So if u show this the user cant understand whats happening. So its advisable to use a toaster Service to show error to user.
https://www.npmjs.com/package/ngx-toastr
getPlayersList() {
this.playerService.getPlayersList().subscribe((res: any) => {
this.playersData = res.data;
}, err => {
this.toasterService.showFailure('Sorry something went wrong');
})
}
In some scenarios if u want to show the error thats coming from api like 500 response u can do in this way
getPlayersList() {
this.playerService.getPlayersList().subscribe((res: any) => {
this.playersData = res.data;
}, err => {
this.toasterService.showFailure(err.err.message);
})
}
Try this:
In your service:
updateNews(data, id) {
return this.http.post(this.baseurl + "/news/update/" + id, data)
}
In your function:
this.newServices.updateNews(result, result.id).subscribe(
(res)=>{
console.log(res)
}),
(error)=>{
console.log(error)
}
I am using axios on my React app to get data from my server (Node). My GET request stays pending in chrome developer tools and does not reach the server if I refresh the app on the provided route (e.g., http://localhost:3000/category/5d68936732d1180004e516cb). However, if I redirect from the home page, it will work.
I have tried different variations of making sure I end my responses on the server end of things.
Several posts have had related problems (e.g., request not reaching the server, POST request does not reach the server) but unfortunately not been helpful in my situation.
Here is my main call in my react app:
componentDidMount() {
console.log('I am here!'); // this gets executed even on page refresh
axios.get(`/api/categories/${this.props.id}`)
.then( (res) => {
this.setState({
title: res.data.category.title,
module: res.data.category.module ? true : false,
...res.data
})
}, (err) => console.log(err))
.catch(err => console.log(err));
}
On my back end I call this function after going through user verification:
module.exports.publishedCategories = async function(req, res) {
try {
// some code that I removed for clarity
res.json({
category,
children,
flagged: flaggedCategories
});
} catch(err) {
console.log(err);
res.sendStatus(500).end();
}
}
Some more code regarding my routing:
index.js
<Route
path='/category/:id'
render={ (props) => {
return <Category id={props.match.params.id} />
}}
/>
I do not get any error messages...
I was overzealous with my initial solution of switching to componentDidUpdate(). This only worked for page refreshes but not for redirects (i.e., I had the reverse problem). My final solution is as follows:
componentDidMount = async () => {
setTimeout( async () => {
this.loadCategory();
}, 10)
}
componentDidUpdate = async (props, state) => {
if(props.match.params.id !== this.props.match.params.id) {
this.loadCategory();
return;
}
return false;
}
loadCategory = async () => {
let result = await axios.get(`/api/categories/${this.props.match.params.id}`);
this.setState({
title: result.data.category.title,
module: result.data.category.module ? true : false,
...result.data
});
}
I am not sure why adding a setTimeout() works for componentDidMount().
As per the documentation componentDidUpdate(), it is good for netork updates however you need to compare prior props with current props.
Unforunately I am not sure how to get around the setTimeout() hack but it seems to work.