You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 04:26:06