简体   繁体   中英

Unable to get JSON response from Express in production

In Development mode, react and express get connected perfectly and I am able to fetch data from backend. But, when using them in production mode, I am getting a status of 200 but unable to get the json response from express.

I am getting this error:

SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data

Backend File is this:

const express = require('express');
const bodyParser = require("body-parser");
const cors = require("cors");
const path = require("path");
const helmet = require("helmet");
const compression = require("compression");

if(process.env.NODE_ENV !== "production") require('dotenv').config();

const app = express();

//middlewares
app.use(helmet());
app.use(compression());
app.use(cors());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));


// serve the react app files in production
if(process.env.NODE_ENV === "production") {
    app.use(express.static(path.join(__dirname, "client/build")));

    app.get("*", (req, res) => {
        res.sendFile(path.join(__dirname, "client/build", "index.html"))
    })
}

//port
const port = process.env.PORT || 5000;
app.listen(port, error => {
    if(error) throw error;
    console.log(`Backend is running on localhost:${port}`);
});

// connection route
app.get("/express", (req, res) => res.json({express: "YOUR EXPRESS BACKEND IS CONNECTED"}));

Backend package.json:

{
  "name": "",
  "version": "1.0.0",
  "description": "",
  "main": "server.js",
  "engines": {
    "node": "12.19.0",
    "npm": "6.14.8"
  },
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "nodemon server.js",
    "mainstart": "concurrently --kill-others-on-fail \"npm start\" \"cd client && yarn start\""
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/g4rry420/armourLine.git"
  },
  "author": "Gurkiran Singh",
  "license": "ISC",
  "bugs": {
    "url": ""
  },
  "homepage": "",
  "dependencies": {
    "body-parser": "^1.19.0",
    "compression": "^1.7.4",
    "concurrently": "^5.3.0",
    "cors": "^2.8.5",
    "dotenv": "^8.2.0",
    "express": "^4.17.1",
    "helmet": "^4.2.0",
    "nodemon": "^2.0.6",
    "path": "^0.12.7"
  }
}

Front end App.js

import React,{ useEffect, useState } from 'react';
import { Route, Switch } from "react-router-dom"

import './App.css';
import Header from "./components/header/header.component"
import ProductItem from './components/product-item/product-item.component';
import Homepage from './pages/homepage.component';
import ProductForm from "./components/product-form/product-form.component";

function App() {

  const [backendData, setBackendData] = useState("No Fetching")

  useEffect(() => {
    callBackedApi()
      .then(res => setBackendData(res.express))
      .catch(err => console.log(err))
  }, [])

  async function callBackedApi(){
    
    const response = await fetch("/express", {
      headers: {
        'Content-Type': 'application/json',
      },
    })
  
    const body = await response.json();

    if(response.status !== 200){
      throw Error(body.message)
    }
    return body;
  }

  return (
    <div className="App">
      {backendData}
      <Header />
      <div>
        <Switch>
          <Route exact path="/" component={Homepage} /> 
          <Route path="/product" component={ProductItem} />
          <Route path="/product-form" component={ProductForm} />
        </Switch>
      </div>
    </div>
  );
}

export default App;

Frontend package.json

{
  "name": "armourline",
  "version": "0.1.0",
  "private": true,
  "proxy": "http://localhost:5000",
  "dependencies": {
    "@testing-library/jest-dom": "^4.2.4",
    "@testing-library/react": "^9.3.2",
    "@testing-library/user-event": "^7.1.2",
    "bootstrap": "^4.5.2",
    "react": "^16.13.1",
    "react-bootstrap": "^1.3.0",
    "react-dom": "^16.13.1",
    "react-icons": "^3.11.0",
    "react-router-dom": "^5.2.0",
    "react-scripts": "3.4.3",
    "react-slick": "^0.27.13"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": "react-app"
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}

  

You have a route ordering problem.

In production, you have this code active:

// serve the react app files in production
if(process.env.NODE_ENV === "production") {
    app.use(express.static(path.join(__dirname, "client/build")));

    app.get("*", (req, res) => {
        res.sendFile(path.join(__dirname, "client/build", "index.html"))
    })
}

Which puts the app.get("*", ...) route BEFORE your app.get("/express", ...) route so the * route will grab the request and send it HTML which won't parse as JSON. The order of your routes matters when they can conflict.

Move your app.get("/express", ...) route BEFORE your app.get("*", ...) route, In fact, the * route should probably be last so all individually specified routes get a chance to grab the request before the * route does. Personally I don't use * routes myself because of some of the issues they can cause.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM