Implementé mi aplicación MERN en Heroku y todo estuvo bien hasta que me di cuenta de un problema cada vez que actualizo la página o intento acceder a una ruta desde la barra de direcciones. Si bien la navegación a través de los enlaces de React Router está bien, tratar de ir directamente a una ruta desde la barra de direcciones URL o actualizar la página hace que la aplicación se rompa y envíe respuestas del servidor directamente al navegador en lugar de representar el componente, para aclarar: si un determinado Se suponía que la ruta debía realizar una GET request y mostrar algunos datos, el JSON real se muestra en la pantalla.
Por lo que he comprobado, esto sucede solo en los componentes que realizan una GET request .
servidor.js
// INITIATE APP const app = express(); // MIDDLEWARE app.use(express.json()); app.use(cookieParser()); app.use(cors()); app.use(passport.initialize()); const isProduction = process.env.NODE_ENV === "production"; // Priority serve any static files isProduction && app.use(express.static(path.resolve(__dirname, "../client/build"))); // CONNECT TO DATABASE // db config const dbConnection = isProduction ? process.env.MONGO_URI_PROD : process.env.MONGO_URI_DEV; mongoose.connect(dbConnection, () => { console.log("Successfully connected to database"); }); // ROUTES const authRouter = require("./routes/auth"); const detailsRouter = require("./routes/details"); const diaryRouter = require("./routes/diary"); const resultsRouter = require("./routes/results"); const settingsRouter = require("./routes/settings"); app.use("/auth", authRouter); app.use("/details", detailsRouter); app.use("/diary", diaryRouter); app.use("/results", resultsRouter); app.use("/settings", settingsRouter); // All remaining requests return the React app, so it can handle routing isProduction && app.get("*", function (request, response) { response.sendFile(path.resolve(__dirname, "../client/build", "index.html")); }); // DEFINE PORTS const port = process.env.PORT || 5000; // START SERVER app.listen(port, () => { console.log(`Server started on port ${port}`); }); Al final del código anterior, justo antes de Define ports , hay esta declaración que incluí para solucionar un problema similar que también ocurre en otras rutas. Pensé que esto evitaría este error en cualquier situación, pero parece que no es así. Puedes probar la aplicación aquí (puedes eliminar la cuenta en /settings después de la prueba).
Me gustaría agradecer a S. Elliott Johnson por la solución que publicaré a continuación para cualquiera que tenga el mismo problema en el futuro:
Esto suena como un comportamiento intencionado. Sus rutas de servidor y sus rutas de React Router NO DEBEN entrar en conflicto.
React Router en realidad no está "enrutando" en ningún lugar desde un sentido HTTP, solo está procesando JavaScript/HTML diferente y almacenando su "ubicación" en la URL.
Cuando se ejecuta una aplicación React, la aplicación React generalmente solo se sirve desde la raíz de su sitio web (o alguna otra "raíz", como mydomain.com/app). Cuando realiza una solicitud
HTTP GETa esa ruta, el servidor backend envía todo el JavaScript, HTML y CSS necesarios para iniciar su aplicación React. Al hacer clic usando React Router simplemente hace que su código React se ejecute en el cliente.Cuando realmente vuelve a cargar la página, su navegador, como sabe, realiza una solicitud
GETde regreso al servidor para esa ruta, por lo que solo obtiene lo que envía su servidor. Usemos algunos ejemplos en los que tiene una aplicación React que se sirve desde mi dominio.com.Ejemplo 1:
El usuario realiza una solicitud GET del navegador a mydomain.com. Reciben la aplicación React de vuelta
El usuario navega a
/auth/login- sin solicitudesHTTP, React simplemente ejecutando códigoEl usuario navega a
/mepara ver su cuenta; de nuevo, lo mismoEl usuario vuelve a cargar la página usando el navegador: se envía una solicitud
HTTP GETal backend y recibirá lo que el backend envíe, ya seaJSONu otra cosa.Realmente tienes dos opciones aquí:
Redirija todas las solicitudes
HTTPa la raíz, lo que significa/,/somethingy/anythingservirá/. Luego aloje su API en otro subdominio, como api.mydomain.comElija una ruta desde la que servir su API, como
mydomain.com/api. Reenviar todas las solicitudes desde cualquier ruta EXCEPTO/apiy sus subrutas a la raíz.
Lo que terminé haciendo fue la opción 2:
Cambié el nombre de mis rutas API anteponiendo /api a todas ellas en server.js . Luego cambié el nombre de todas las llamadas API en React en consecuencia. Ese extracto de código
isProduction && app.get("*", function (request, response) { response.sendFile(path.resolve(__dirname, "../client/build", "index.html")); }); en server.js se ocupó de las solicitudes GET ejecutadas en la actualización de la página, asegurándose de que Node siempre sirva index.html para proporcionar esas solicitudes.