1

I have been working on this issue for 2 days, looked at various pages and cannot find a single solution that would work.

Please only reply if you know how to write them with async await functions and please reply if you know the answer of fetch api. I am not looking for axios solutions for the time being. I have a backend server which runs on port 8000 of localhost, frontend runs on port 3000. Front end is written in React, backend is written in Node/Express.

I am able to successfully make a GET request from backend server but the POST request fails for some reason with the error "VM942:1 POST http://localhost:8000/frontend-to-backend 500 (Internal Server Error)"

Backend server has this error: SyntaxError: Unexpected token u in JSON at position 0 at JSON.parse ()

  // React-To-Node-Connection
  // React "App.js" file
  // "package.json" file contains this
  // "proxy": "http://localhost:8000"
  useEffect(() => {
    const getBackend = async () => {
      const res = await fetch('backend-to-frontend');
      const data = await res.json();

      if (!res.ok) {
        throw new Error(`Cannot get data from backend server. HTTP Status: ${res.status}`);
      }

      console.log(data.message);
      // Prints "Hi from backend!"
    }

    getBackend();

    const postBackend = async () => {

      try {
        const res = await fetch('http://localhost:8000/frontend-to-backend',
          {
            method: 'POST',
            mode: 'no-cors',
            body: JSON.stringify({ message: 'Hi from frontend!' }),
            headers: {
              'Accept': 'application/json',
              'Content-Type': 'application/json'
            }
          }
        );

        if (res.ok) {
          const data = await res.json();
          console.log(data);
        }
      } catch (error) {
        console.error(error);
      }
    }

    postBackend();

  }, []);

Now the backend code:

app.get('/backend-to-frontend', (req, res) => {
    res.json({ message: 'Hi from backend!' });
});

app.post('/frontend-to-backend', (req, res) => {
    try {
        const reactMessage = JSON.parse(req.body.data);
        console.log(`message: ${reactMessage}`);
    } catch (err) {
        console.error(err);
    }
});

How to fix this? Please help!

Full backend server code can be found here:

const express = require("express");

const app = express();

app.use(express.urlencoded({ extended: true }));

app.get('/backend-to-frontend', (req, res) => {
    res.json({ message: 'Hi from backend!' });
});

app.post('/frontend-to-backend', (req, res) => {
    try {
        const reactMessage = JSON.parse(req.body.data);
        console.log(`message: ${reactMessage}`);
    } catch (err) {
        console.error(err);
    }
});

const port = process.env.PORT || 8000;

app.listen(port, function () {
    console.log(`Backend server started on port ${port}.`);
});
Codecygen
  • 121
  • 1
  • 1
  • 10
  • 2
    A 500 means there was an error when the backend runs. Given there is one line of code that could throw an error, I'd say `JSON.parse(req.body.data)` fails. I'd assume it's most likely [How to access the request body when POSTing using Node.js and Express?](https://stackoverflow.com/q/11625519) – VLAZ Feb 04 '22 at 06:53
  • Backend error is this: SyntaxError: Unexpected token u in JSON at position 0 at JSON.parse () – Codecygen Feb 04 '22 at 07:01

3 Answers3

2

with no-cors, you can only use simple headers, so you cannot POST JSON (see: Supplying request options)

Try urlencoded:

   const postBackend = async() => {

     try {
       const res = await fetch('http://localhost:8000/frontend-to-backend', {
         method: 'POST',
         mode: 'no-cors',
         headers: {
           'Content-Type': 'application/x-www-form-urlencoded'
         },
         body: new URLSearchParams({
           'message': 'Hi from frontend!'
         })
       });

       if (res.ok) {
         const data = await res.json();
         console.log(data);
       }
     } catch (error) {
       console.error(error);
     }
   }

   postBackend();

and on the server, don't parse req.body, as it's already done by middleware:

app.post('/frontend-to-backend', (req, res) => {
    console.log('req.body: ', req.body);
    try {
        const reactMessage = req.body.message; 
traynor
  • 5,490
  • 3
  • 13
  • 23
  • If I remove no Cors, frontend throws error. Access to fetch at 'http://localhost:8000/frontend-to-backend' from origin 'http://localhost:3000' has been blocked by CORS policy: – Codecygen Feb 05 '22 at 05:39
  • 1
    @Gingercook I didn't say anything about removing `no cors` – traynor Feb 05 '22 at 12:52
1

req.body.data may be an object (check with debugger). If so, you might try to stringify before parsing :

JSON.parse(JSON.stringify(req.body.data))
benek
  • 2,088
  • 2
  • 26
  • 38
0

I finally found the answer, here is my sample code. I did not change the React code that much so it is pretty much same, I removed the no cors section and added cors to Express JS code.

Here is my React code.

  // React-To-Node-Connection
  // "package.json" file has the following line
  // "proxy": "http://localhost:8000"
  // React Code
  useEffect(() => {
    const getBackend = async () => {
      const res = await fetch('/backend-to-frontend');
      const data = await res.json();

      if (!res.ok) {
        throw new Error(`Cannot get data from backend server. HTTP Status: ${res.status}`);
      }

      console.log(data.message);
    }

    getBackend();

    const postBackend = async () => {

      try {

        await fetch('http://localhost:8000/frontend-to-backend',
          {
            method: 'POST',
            body: JSON.stringify({ message: 'Hi from frontend!' }),
            headers: {
              'Content-Type': 'application/json'
            }
          }
        );

      } catch (err) {
        console.error(err);
      }
    }

    postBackend();

  }, []);

And here is my Express JS code.

const express = require("express");

const app = express();

app.use(express.urlencoded({ extended: true }));

// Express JS Code
const cors = require('cors');
app.use(express.json());
app.use(cors());

app.get('/backend-to-frontend', (req, res) => {
    res.json({ message: 'Hi from backend!' });
});

app.post('/frontend-to-backend', (req, res) => {
    try {
        console.log(req.body.message);
    } catch (err) {
        console.error(err);
    }
});

const port = process.env.PORT || 8000;

app.listen(port, function () {
    console.log(`Backend server started on port ${port}.`);
});

Thanks.

Codecygen
  • 121
  • 1
  • 1
  • 10
  • I was having the same issue. Spent a few hours trying to find an answer and both this answer and @traynor answer worked for me. I've search for the reason why your answer works but can't find a good reason. Do you know why adding cors made it work? I'm guessing if cors is added/enabled on the server then, for some reason, it allows the post data. Maybe because it's coming from an allowed origin or from the same origin...? – Tony Lisanti Jul 19 '22 at 15:45
  • @TonyLisanti By default, web browsers prevent client-side JavaScript code from making cross-domain HTTP requests, in order to prevent malicious actors from sending requests to third-party servers on behalf of unsuspecting users. This is known as the "same-origin policy." To allow your client-side code to make HTTP requests to your server-side API running on a different domain (like from localhost:3000 to localhost:3001), you need to configure CORS on your server-side component that can be done by a middleware like cors to enable CORS on your Express.js server. – fflores Mar 22 '23 at 11:05