Express服务器是否需添加app.get()?Docker部署报Cannot GET /
我正尝试将应用部署到AWS,但Docker镜像运行异常,在localhost:8080返回“Cannot GET /”。该应用是跟随Udemy课程构建的,服务器代码如下:
import express from "express"; import { readdirSync } from "fs"; import cors from "cors"; import mongoose from "mongoose"; const fileuploader = require("express-fileupload"); const morgan = require("morgan"); require("dotenv").config(); const app = express(); // db connection mongoose .connect(process.env.DATABASE, { useNewUrlParser: true, useFindAndModify: false, useUnifiedTopology: true, useCreateIndex: true, }) .then(() => console.log("DB Connected")) .catch((err) => console.log("DB Connection Error: ", err)); // middlewares app.use(cors()); app.use(morgan("dev")); app.use(express.json()); //for image upload app.use(fileuploader()); // route middleware readdirSync("./routes").map((r) => app.use("/api", require(`./routes/${r}`))); const port = process.env.PORT || 8080; app.listen(port, () => console.log(`Server is running on port ${port}`));
我排查后推测,问题可能出在服务器未添加app.get("/", (req, res) => {...}),该根路由实际存在于前端
FROM node:lts-alpine WORKDIR /app COPY package*.json ./ COPY client/package*.json client/ RUN npm run install-client --omit=dev COPY server/package*.json server/ RUN npm run install-server --omit=dev COPY client/ client/ RUN npm run build --prefix client COPY server/ server/ USER node CMD [ "npm", "start", "--prefix", "server" ] EXPOSE 8080
补充说明:Docker镜像可正常启动服务器并连接数据库,但网页无法加载。
核心问题分析
你的推测方向沾边,但没说到根本——问题是Express服务器既没托管前端构建好的静态资源,也没处理单页应用(SPA)的路由回退逻辑。
具体解决方案
添加静态资源托管与SPA路由回退
在server代码的app.listen之前,插入以下代码:import path from 'path'; // 托管前端build目录下的静态文件(CSS、JS、图片等) app.use(express.static(path.join(__dirname, '../client/build'))); // 所有非API开头的请求,都返回前端的index.html,交给前端路由处理 app.get('*', (req, res) => { res.sendFile(path.join(__dirname, '../client/build/index.html')); });解释:你的Dockerfile已经执行了
npm run build --prefix client生成了前端生产环境产物,但Express不会自动识别并托管这些文件,也不知道如何处理SPA的路由(比如/或其他前端页面路径),必须手动配置。确认路径正确性
根据Dockerfile的目录结构,容器内server代码在/app/server,前端build产物在/app/client/build,所以../client/build这个相对路径是正确的,不用修改。本地预验证
先在本地执行npm run build --prefix client,确认client/build目录生成且内容完整,再构建Docker镜像,避免因前端构建失败导致的问题。
关于根路由的疑问
不需要单独写app.get("/"),因为上面的app.get('*')已经覆盖了包括根路径在内的所有非API请求,会自动返回前端的index.html,由前端的Route组件负责渲染对应页面。
内容的提问来源于stack exchange,提问作者src2012

