Search code examples
node.jsexpressnpmexpress-session

node express-session not saving across pages


I can't figure out why when i goto localhost:8080 it saves the session (appears to) but then when I goto the next URL localhost:8080/me the session is empty again.

const express = require("express");
const app = express();
const port = 8080;
const router = express.Router();
const session = require('express-session');

app.use(session({
  secret: 'work hard',
  resave: true,
  saveUninitialized: false
}))

app.get("/", function(req,res, next){
    req.session.myname = "nathan";
    console.log(req.session.myname);
});


app.get("/me", function(req,res, next){

    console.log(req.session.myname);
});

app.listen(port, () => console.log(`Example app listening on port ${port}!`))

when I try the app.sendStatus method as shown by the first contributor below (in the answers), it works, but not if I use ajax???

    $("#register").on("click", function(){
         $.ajax({url: "http://localhost:8080/"});
    });


    $("#me").on("click", function(){
         $.ajax({url: "http://localhost:8080/me"});
    });

Solution

  • The reason is you didn't send a response with a set-cookie header to client.

    The Set-Cookie HTTP response header is used to send cookies from the server to the user agent, so the user agent can send them back to the server later.

    You can use res.sendStatus(), res.send(), res.end() and res.json() etc. Send a response to client.

    E.g.

    app.js:

    const express = require('express');
    const app = express();
    const port = 8080;
    const router = express.Router();
    const session = require('express-session');
    const fs = require('fs');
    const path = require('path');
    
    app.use(
      session({
        secret: 'work hard',
        resave: true,
        saveUninitialized: false,
      }),
    );
    
    app.get('/', function(req, res, next) {
      req.session.myname = 'nathan';
      console.log(req.session.myname);
      const htmlContent = fs.readFileSync(path.resolve(__dirname, './public/app.html')).toString();
      res.send(htmlContent);
    });
    
    app.get('/me', function(req, res, next) {
      console.log(req.session.myname);
      res.sendStatus(200);
    });
    
    app.get('/ajax', function(req, res) {
      console.log('req.session.myname: ', req.session.myname);
      res.sendStatus(200);
    });
    
    app.listen(port, () => console.log(`Example app listening on port ${port}!`));
    

    After doing this, your client(can be a browser) will receive these response headers:

    HTTP/1.1 200 OK
    X-Powered-By: Express
    Content-Type: text/plain; charset=utf-8
    Content-Length: 2
    ETag: W/"2-nOO9QiTIwXgNtWtBJezz8kv3SLc"
    set-cookie: connect.sid=s%3A-QI2kuY8IlxdAZw96xqG_npmuKwFhg0s.tKcPZgcHhHvXG0kqgKzwzJJ7kn2JkPOMG9R%2FyQaJwPw; Path=/; HttpOnly
    Date: Mon, 23 Dec 2019 06:00:24 GMT
    Connection: keep-alive
    

    The browser will set cookie automatically. Then, you goto the next /me route, the browser will send this cookie automatically with request header.

    E.g.

    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
    Accept-Encoding: gzip, deflate, br
    Accept-Language: zh-CN,zh;q=0.9
    Cache-Control: no-cache
    Connection: keep-alive
    Cookie: connect.sid=s%3A-QI2kuY8IlxdAZw96xqG_npmuKwFhg0s.tKcPZgcHhHvXG0kqgKzwzJJ7kn2JkPOMG9R%2FyQaJwPw
    Host: localhost:8080
    Pragma: no-cache
    Upgrade-Insecure-Requests: 1
    User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36
    

    In your server side /me controller, express-session middleware will parse the cookie and you will get the value of myname from req.session.myname property.

    Update:

    ./public/app.html:

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <meta http-equiv="X-UA-Compatible" content="ie=edge" />
        <title>Document</title>
      </head>
      <body>
        <main>
          app
          <button id="me">Click Me</button>
        </main>
        <script
          src="https://code.jquery.com/jquery-3.4.1.min.js"
          integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo="
          crossorigin="anonymous"
        ></script>
        <script>
          window.onload = function() {
            $('#me').on('click', function() {
              $.ajax({ url: 'http://localhost:8080/ajax' }).then(() => {
                console.log('success');
              });
            });
          };
        </script>
      </body>
    </html>
    

    You can get the value of myname as well. Here is the server-side logs:

    Example app listening on port 8080!
    nathan
            req.session.myname:  nathan