404 无法在 Golang 服务器上使用 React 应用程序

问题描述 投票:0回答:1

在开发环境中运行reactjs应用程序时,我的重定向工作完美(

npm run dev
),正确重定向到主页。但是当我在 golang 上提供相同的应用程序时,在
npm run build
之后,重定向不起作用。

应用程序.jsx

import {
  Route,
  createBrowserRouter,
  createRoutesFromElements,
  RouterProvider,
  Navigate,
} from "react-router-dom";
import HomePage from "./pages/Home/HomePage";
import MainLayout from "./layouts/MainLayout";
import { useGlobal } from "./GlobalState";
import PodPage from "./pages/Pods/PodPage";

const App = () => {
  const { isClusterConnected } = useGlobal();

  const router = createBrowserRouter(
    createRoutesFromElements(
      <>
        <Route path="/" element={<MainLayout />}>
          <Route
            index
            element={
              isClusterConnected ? <Navigate to="/pods" /> : <HomePage />
            }
          />
          <Route path="*" element={<Navigate to="/" replace />} />
          <Route
            path="/pods"
            element={!isClusterConnected ? <Navigate to="/" /> : <PodPage />}
          />
        </Route>
      </>
    )
  );

  return <RouterProvider router={router} />;
};

export default App;

但是在golang上运行相同,在构建react应用程序并将其嵌入到golang中之后,如果我在url中有路径,localhost:8080可以工作,那么它总是给出404,但是当我在localhost:8080 / pods或/不存在时刷新它给出 404 错误。

main.go

//go:embed dist/*
var distFS embed.FS

func main() {
    r := mux.NewRouter()

    k8sApiRouter := r.PathPrefix("/api/k8s").Subrouter()
    r.HandleFunc("/api/k8s/set-client", api.Setk8sClient).Methods("POST")
    r.HandleFunc("/api/k8s/cluster-connected", api.ClusterConnected).Methods("GET")
    r.HandleFunc("/api/k8s/disconnect", api.SetClientSetToNil).Methods("GET")
    r.HandleFunc("/execute", executeCommand)
    k8sApi.RegisterK8sRouters(k8sApiRouter)

    // Serve your ReactJS frontend (assuming it's in a "build" directory)
    // Create a subdirectory in the embedded file system
    subFS, err := fs.Sub(distFS, "dist")
    if err != nil {
        fmt.Println("Failed to locate embedded files:", err)
        return
    }
    r.PathPrefix("/").Handler(http.FileServer(http.FS(subFS)))

    handler := config.CORS.Handler(r)

    port := ":8080"
    fmt.Println("Server started on " + port)
    http.Handle("/", handler)
    http.ListenAndServe(port, nil)
}

func executeCommand(w http.ResponseWriter, r *http.Request) {
    if r.Method == "OPTIONS" {
        return
    }

    if r.Method != "POST" {
        http.Error(w, "Invalid request method", http.StatusMethodNotAllowed)
        return
    }

    cmd, err := io.ReadAll(r.Body)
    if err != nil {
        http.Error(w, "Error reading command", http.StatusBadRequest)
        return
    }

    output, err := exec.Command("sh", "-c", string(cmd)).CombinedOutput()
    if err != nil {
        http.Error(w, "Failed to execute command", http.StatusInternalServerError)
        return
    }

    w.Header().Set("Content-Type", "text/plain")
    w.Write(output)
}

这里有明显的 404 问题,假设我的 React 应用程序运行 localhost:3000,如果我在任何路径上刷新,它会将我带到主页。但是当我在 golang 中提供 React 应用程序时,转到 localhost:8080 它可以工作,以编程方式导航也可以工作,但是当我单击刷新浏览器按钮时,它给出 404,在 localhost:8080 上刷新将我带到主页,但其中的任何路径给出 404

我在 golang 中尝试过这个

// Custom NotFound handler
    r.NotFoundHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        http.Redirect(w, r, "/", http.StatusSeeOther)
    })

不确定修复是否在 React 应用程序或 golang 项目中。

go gorilla
1个回答
0
投票

为了解决这个问题,您需要修改处理程序来检查文件是否存在,并在文件不存在时提供index.html。这是 Go 服务器代码的更新版本:

//go:embed dist/*
var distFS embed.FS

func main() {
    r := mux.NewRouter()

    // Create a subdirectory in the embedded file system
    subFS, err := fs.Sub(distFS, "dist")
    if err != nil {
        fmt.Println("Failed to locate embedded files:", err)
        return
    }

    // Serve static files and index.html for frontend routes
    r.PathPrefix("/").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        filePath := path.Clean(r.URL.Path)
        if filePath == "/" {
            filePath = "index.html"
        } else {
            filePath = strings.TrimPrefix(filePath, "/")
        }

        file, err := subFS.Open(filePath)
        if os.IsNotExist(err) || filePath == "index.html" {
            http.ServeFile(w, r, "dist/index.html")
            return
        } else if err != nil {
            http.Error(w, "Internal Server Error", http.StatusInternalServerError)
            return
        }
        defer file.Close()

        http.FileServer(http.FS(subFS)).ServeHTTP(w, r)
    })

    handler := config.CORS.Handler(r)

    port := ":8080"
    fmt.Println("Server started on " + port)
    http.Handle("/", handler)
    http.ListenAndServe(port, nil)
}
© www.soinside.com 2019 - 2024. All rights reserved.