Docker中Gin服务无法访问React dist目录致根路径404问题
问题
用Gin框架开发的Go服务,本地可通过根路径正常渲染dist目录下的React应用,但在Docker容器中运行时,/api端点工作正常,根路径始终返回404错误。
服务代码
func main() { db := initDB() defer db.Close() gin.SetMode(GIN_MODE) router := gin.Default() router.Use(gzip.Gzip(gzip.DefaultCompression)) apiRouter := router.Group("/api") v1Router := apiRouter.Group("/v1") misc.RegisterRoutes(v1Router) pastesHandler := pastes.NewHandler(db) pastesHandler.RegisterRoutes(v1Router) router.NoRoute(gin.WrapH(http.FileServer(http.Dir(DIST_DIR)))) server := &http.Server{ Addr: ":" + PORT, Handler: router, ReadTimeout: 10 * time.Second, WriteTimeout: 10 * time.Second, MaxHeaderBytes: 1 << 20, // 1MB } log.Print("PWD") log.Println(os.Getwd()) log.Println(os.ReadDir(".")) log.Println("DIST_DIR", DIST_DIR) log.Println(os.ReadDir(DIST_DIR)) log.Println("Listening at port", PORT) log.Fatal(server.ListenAndServe()) }
容器运行日志
pasteforge-1 | 2024/08/04 16:06:55 PWD pasteforge-1 | 2024/08/04 16:06:55 /app <nil> pasteforge-1 | 2024/08/04 16:06:55 [- .env d dist/ - server] <nil> pasteforge-1 | 2024/08/04 16:06:55 DIST_DIR "/app/dist" pasteforge-1 | 2024/08/04 16:06:55 [] open "/app/dist": no such file or directory pasteforge-1 | 2024/08/04 16:06:55 Listening at port 8080
Dockerfile
FROM node:22-slim AS frontend-build ENV PNPM_HOME="/pnpm" ENV PATH="$PNPM_HOME:$PATH" RUN corepack enable WORKDIR /app # Build the frontend COPY "package.json" "pnpm-lock.yaml" ./ RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile COPY . . RUN pnpm run build # build the backend FROM golang:1.22-alpine AS server-build WORKDIR /app COPY "./backend/go.sum" . COPY "./backend/go.mod" . RUN go mod download COPY backend/ . RUN go build -o server # Final stage: Copy the frontend and Go server into a new image FROM alpine:3.20 WORKDIR /app COPY --from=frontend-build /app/dist ./dist COPY --from=server-build /app/server . COPY --from=server-build /app/.env ./.env ENV ADDR="0.0.0.0" ENV PORT=8080 ENV GIN_MODE=release ENV DIST_DIR="/app/dist" # Expose the port your Go server listens on EXPOSE 8080 USER root CMD ["./server"]
已做排查
- 确认容器内环境变量配置正确
- 验证dist目录确实存在于容器内
- 服务以root身份运行
- 尝试过绝对路径与相对路径指向dist目录
解决方案
1. 修复环境变量引号问题
从容器日志可见DIST_DIR的值为"/app/dist"(包含双引号),这是因为Dockerfile中ENV DIST_DIR="/app/dist"的引号被当作变量值的一部分,导致路径解析错误。修改Dockerfile中的环境变量定义,去掉引号:
ENV DIST_DIR=/app/dist
2. 适配React单页应用路由
React是单页应用,所有非API路由需指向index.html,原代码的NoRoute处理无法适配SPA路由,调整为:
import "path" // 注册静态文件服务 router.StaticFS("/", http.Dir(DIST_DIR)) // 处理SPA路由:未匹配的请求返回index.html router.NoRoute(func(c *gin.Context) { c.File(path.Join(DIST_DIR, "index.html")) })
若静态资源存放在dist/static目录下,可优化为:
import "strings" import "path" fs := http.FileServer(http.Dir(DIST_DIR)) router.NoRoute(func(c *gin.Context) { // 静态资源请求正常转发 if strings.HasPrefix(c.Request.URL.Path, "/static/") { c.Request.URL.Path = c.Request.URL.Path[len("/"):] fs.ServeHTTP(c.Writer, c.Request) return } // 非静态资源请求返回index.html c.File(path.Join(DIST_DIR, "index.html")) })
3. 验证路径正确性
重新构建镜像并运行容器,检查日志中os.ReadDir(DIST_DIR)是否能正常列出dist目录下的文件,确认路径解析无误。
内容的提问来源于stack exchange,提问作者Shravan
相关产品推荐
相关产品推荐

