0

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);
         });
   }
 }));
});
codefriend
  • 33
  • 7
  • Possible duplicate of [Error: Can't set headers after they are sent to the client](http://stackoverflow.com/questions/7042340/error-cant-set-headers-after-they-are-sent-to-the-client) – John Weisz Jan 18 '17 at 21:13
  • @JohnWeisz - I wouldn't call this a dup of that. The issue here is WHY does this specific code generate that error message and what are the offending parts of this code. That other answer does not address anything about what is wrong with this specific code. – jfriend00 Jan 18 '17 at 21:21
  • @jfriend00 -- Although I do agree with you, I also believe this comes down to a matter of taste and personal preferences in this case, considering this is a classical problem of server-side programming, where understanding the _general principle_ behind the issue is itself the answer: _no content writing before headers, or use output buffering_. – John Weisz Jan 20 '17 at 12:06

1 Answers1

0

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.

jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • After rendering dashboard,redux updated my state of headers by calling UPDATE_HEADER action and i wanna set those updated headers in state as cookie.Also html element is nothing but componentHTML. – codefriend Jan 18 '17 at 21:54
  • Just let me know how to set a cookie after res.render or for deeper info about the problem ,Check [link](https://redux-oauth-demo.herokuapp.com) and check the server state and headers part in widget shown there under auth section – codefriend Jan 18 '17 at 21:58
  • @Coder - You can't set a cookie AFTER you send the response. You need to set it before. The cookie is part of the response. You can move the `res.cookie()` before you do `res.render()` and remove the `res.end(html)`. If you're relying on some side effect of `res.render()` and that's why you want to set the cookie after you send the rendered HTML, then you have to fix the design. You simply can't do that. You could render manually into a variable (which will not send the result) and then set the cookie and then send the html. But really, you should remove the side effect design. – jfriend00 Jan 18 '17 at 22:03
  • Okay.Thanks for the info.I am making a renderHTML function and call my component to be rendered there instead of res.render.And will then set a cookie. – codefriend Jan 18 '17 at 22:16
  • @Coder - Sounds like a much better design. – jfriend00 Jan 18 '17 at 22:50