Home > database >  Fetch in vue 3 stops backend and does nothing after working fine one time
Fetch in vue 3 stops backend and does nothing after working fine one time

Time:12-05

So, my problem is when I try to login in my vue app, the backend automatically stops when I try to fetch from it an array of objects.

To be more specific. This is my fetch "attempt" to retrieve the objects from the database.

let url = utils.url;
    let requestParam = utils.globalRequestParameters;
    requestParam.method = "GET";
    requestParam.body = null;
    if (cars.value.length == 0) {
      fetch(url   "cars", requestParam).then((res) =>
        res.json().then(async (res) => {
          store.dispatch("Car/fetchCars", res);
          fetch(url   "users", requestParam).then((users) =>
            users.json().then((users) => {
              for (let car of res) {
                let userCar = Object.values(users).find(
                  (a) => a.id == car.userId
                );
                car.userName = userCar.lastName   " "   userCar.firstName;
              }
            })
          );
        })
      );
    }

And login in view Login.vue

let requestParameters = utils.globalRequestParameters;
        requestParameters.method = "POST";
        requestParameters.body = JSON.stringify(data);

        fetch(utils.url   "login", requestParameters).then((res) => {
          res.json().then((res) => {
            this.mesaj = res.message;
            console.log("token:"   res.token);
            if (res.token) {
              localStorage.setItem("token", res.token);
              console.log("token:"   res.token);
              console.log("id:"   res.id);
              let id = res.id;
              requestParameters.method = "GET";
              requestParameters.body = null;
              this.$store.dispatch("login", true);
              fetch(utils.url   "users/"   id, requestParameters).then(
                (res) => {
                  res.json().then((res) => {
                    console.log("Jos de tot");
                    this.$store.dispatch("User/setUser", res);
                    console.log(this.$store.state.User.user);
                    this.$router.push("/");
                  });
                }
              );
            }
          });
        });
      }
    },

Note. cars is a computed value that return store.state.cars and utils is

let url = "http://127.0.0.1:3000/";

let globalRequestParameters = {
  method: "GET",
  mode: "cors",
  cache: "no-cache",
  credentials: "same-origin",
  headers: {
    "Content-Type": "application/json",
  },
  redirect: "follow",
  referrerPolicy: "no-referrer",
};

module.exports.globalRequestParameters = globalRequestParameters;
module.exports.url = url;

Here at the first fetch the backend stops and also the fetch it is not done.

And the backend route is


router.get('/cars', async (req, res) => {
    res.json(await functions.getAllCars(req,res));
})

getAllCars = async (req, res) => {
  const snapshot = await db.collection("Cars").get();
  let cars = [];
  snapshot.forEach((doc) => {
    let car = {
      id: doc.id,
      userId: doc.data().userId,
      manufacturer: doc.data().manufacturer,
      model: doc.data().model,
      color: doc.data().color,
      plate: doc.data().plate,
      price: doc.data().price,
      description: doc.data().description
    };
    cars.push(car);
  });

  res.status(200).send(cars);
  return
};

router.get("/users/:id", async (req, res) => {
  res.json(await functions.getUserById(req.params.id, res));
});

getUserById =  (id, res) => {
   db
    .collection("Users")
    .doc(id)
    .get()
    .then((response) => {
      let user = {};
      user.id = response.id;
      user.firstName = response.data().firstName;
      user.lastName = response.data().lastName;
      user.gender = response.data().gender;
      user.jobTitle = response.data().jobTitle;
      user.phone = response.data().phone;
      user.email = response.data().email;
      user.isAdmin = response.data().isAdmin;
      res.status(200).send(user);
      return
    })
    .catch((err) => {
      res.status(404).send({ message: "User not found" });
      return
    });
};

The user is retrieved correctly, I see it in console through a console log, but the messages that I get in the terminal and console are:

enter image description here

enter image description here

*As a final note. I use vue 3, node.js version 16.13.0 and Firestore as Database. And yesterday everything was working perfectly fine on my other computer but I had to go somewhere and use my laptop. Maybe there is something about my laptop. All I did was just to install the modules for the front and back

CodePudding user response:

I think this has nothing to do with Vue - it is simply the problem of your Express backend code

ERR_HTTP_HEADERS_SENT: Cannot set headers after they are sent to the client

As described here:

That particular error occurs whenever you try to send more than one response to the same request and is usually caused by improper asynchronous code.

getAllCars

getAllCars is async function with await inside - as soon as this await is hit (together with db.collection("Cars").get() call), function returns Promise which is awaited at res.json(await functions.getAllCars(req,res));

When the DB call finishes, the rest of the method is executed including res.status(200).send(cars) - this will send the cars array to the client and returns undefined (this is what simple return does) and res.json(undefined) is executed causing the error above (you are trying to send second response)

getUserById

You say that this handler works fine but I really doubt it - from what I see, this should NOT work either

You are calling it with res.json(await functions.getUserById(req.params.id, res));. To await actually doing something, the awaited function must return a Promise (either implicitly by using await inside or explicitly) or general "thenable" object. The getUserById function returns nothing (return statements inside then() or catch() does not count! ...those are different functions)

This problem can be fixed by doing return db.collection("Users").doc(id).get().then() but then you will get same error as in getAllCars case

Correct pattern

  1. Do not use res.status(200).send() and res.json() together
  2. For the sake of sanity (at least until you really know what you are doing) do not mix promises with async/await
  3. async functions should return the data (do not use return without "argument")

Following code shows both Promise based and async/await style (it "pseudo code" in the sense I did not tested it but hopefully you get the idea)

router.get('/cars', async (req, res) => {
  try {  
    const response = await functions.getAllCars()
    res.status(200).json(response);
  } catch() {
    res.sendStatus(500)
  }
})

getAllCars = async () => {
  const snapshot = await db.collection("Cars").get();
  let cars = [];
  snapshot.forEach((doc) => {
    let car = {
      id: doc.id,
      userId: doc.data().userId,
      manufacturer: doc.data().manufacturer,
      model: doc.data().model,
      color: doc.data().color,
      plate: doc.data().plate,
      price: doc.data().price,
      description: doc.data().description
    };
    cars.push(car);
  });

  // res.status(200).send(cars); //* should be handled by caller
  return cars  //* return the data
};

router.get("/users/:id", async (req, res) => {
  functions.getUserById(req.params.id)
    .then((response) =>  {
      if(response === null)
        res.status(404).json({ message: "User not found" });
      else
        res.status(200).json(response);
    })
    .catch(er) {
      res.status(500).send(er.message)
    }
});

getUserById =  (id) => {
   return db  //* return the promise
    .collection("Users")
    .doc(id)
    .get()
    .then((response) => {
      let user = {};
      user.id = response.id;
      user.firstName = response.data().firstName;
      user.lastName = response.data().lastName;
      user.gender = response.data().gender;
      user.jobTitle = response.data().jobTitle;
      user.phone = response.data().phone;
      user.email = response.data().email;
      user.isAdmin = response.data().isAdmin;
      // res.status(200).send(user); //* should be handled by caller
      return user //* return the data
    })
    .catch((err) => {    
      return null
    });
};
  • Related