ExpressJS: res.redirect() does not work. How to redirect in single page app?

Viewed 1240

Issue:

I have a static single page application in which I press on a Submit input that sends a POST request using Axios from a Vue component to an Express server in which I handle the POST and try to redirect to another page, but res.redirect("/home") and/or res.sendFile(path.join(__dirname, "../dist/index.html")); do not redirect.

Expected behaviour:

I would like to redirect to /home after submit. Everything else works just fine.

Server File:

const history = require('connect-history-api-fallback');
const path = require("path");

// serve the Vue Interface
const buildLocation = path.join(__dirname, "../dist");
app.use(express.static(buildLocation));
app.use(history({
  disableDotRule: true,
  verbose: true
}));
app.use(express.static(buildLocation));

app.get('/home', function(req, res) {
  res.sendFile(path.join(__dirname, "../dist/index.html"));
});


app.post("/dhcpIP", function (req, res) {
  // check if request body is empty
  if (req.body.constructor === Object && Object.keys(req.body).length === 0)
    return;
  // doing things that work
  res.redirect('/'); // this doesn't work
});

const http_server = http.createServer(app);

http_server.listen(http_port);

I build the Vue CLI application so that I can obtain the dist folder. In the dist folder I have an index.html that contains the whole application.

Vue component that sends the POST request:

<template>
  <form action="javascript:void(0);" @submit="sendData" novalidate="true">
    <input type="text"/>
    <input type="password"/>
    <input type="submit"/>
  </form>
</template>

<script>
import axios from "axios";

const serverURL = location.origin;
const server = axios.create({ baseURL: serverURL });

export default {
  name: "DHCP",
  data() {
    return {
      visible: false,
      ssid: "",
      password: ""
    };
  },
  methods: {
    sendData: function() {
      if (this.ssid === "" || this.password === "") return;
      let currentUrl = window.location.pathname;
      console.log("currentUrl:");
      console.log(currentUrl);
      server
        .post(currentUrl, { ssid: this.ssid, password: this.password })
        .then(res => {
          console.log(res);
        })
        .catch(err => {
          console.log(err);
        });
    }
  }
};
</script>

Router File

import Vue from "vue";
import VueRouter from "vue-router";
import Home from "../views/Home.vue";

Vue.use(VueRouter);

const routes = [
  {
    path: "/",
    redirect: "/home",
    component: Home,
  },
  {
    path: "/home",
    name: "Home",
    component: Home,
  },
  {
    path: "/dhcpIP",
    name: "DHCP",
    component: () => import(/* webpackChunkName: "dhcpIP" */ "../views/DHCP.vue")
  },
];

const router = new VueRouter({
  mode: "history",
  // base: process.env.BASE_URL,
  routes,
});

export default router;

I have tried writing as little code as possible.

3 Answers

In your post route you are already returning something

app.post("/dhcpIP", function (req, res) {
  // check if request body is empty
  if (req.body.constructor === Object && Object.keys(req.body).length === 0)
    return;
  // doing things that work
  res.redirect('/'); // this doesn't work
});

The return statement ends the function execution. That being said: You are returning "some things that work" and after that you use the res.redirect method, which is ignored because the function has already returned a value.

I have figured out the problem using this SO thread. Apparently, if you are doing an AXIOS post, you can't redirect from the Express server and you must handle the redirect in the AXIOS method.
I haven't found any explanation or documentation on this subject yet. When I do I will update this answer.

I did it like this:

Server file:

app.post("/dhcpIP", function (req, res) {
  // check if request body is empty
  if (req.body.constructor === Object && Object.keys(req.body).length === 0)
    return;
  // doing things that work

  if(errors.length != 0) {
    res.sendStatus(500);
  } else
  res.sendStatus(200);
});

Vue component:

    sendData: function() {
      if (this.ssid === "" || this.password === "") return;
      let currentUrl = window.location.pathname;
      server
        .post(currentUrl, { ssid: this.ssid, password: this.password })
        .then(res => {
          if(res.status == 200) {
            alert("Settings have been saved.");
            window.location = currentUrl;
          } else {
            alert("Something went wrong. Please try again");
          }
        })
        .catch(err => {
          console.log(err);
        });
    }

Related