package httpx import ( "net/http" "os" "path" "strings" ) const basename = "/" type NotFoundHandler struct { fs http.FileSystem fileServer http.Handler } // NewNotFoundHandler 静态资源服务:命中即返回文件,否则回退到 index.html(前端 SPA 路由) func NewNotFoundHandler(fs http.FileSystem) NotFoundHandler { return NotFoundHandler{ fs: fs, fileServer: http.FileServer(fs), } } func (n NotFoundHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { if strings.HasPrefix(r.URL.Path, "/api/") { http.Error(w, "not found", http.StatusNotFound) return } filePath := strings.TrimPrefix(path.Clean(r.URL.Path), basename) if len(filePath) == 0 { filePath = basename } file, err := n.fs.Open(filePath) switch { case err == nil: n.fileServer.ServeHTTP(w, r) _ = file.Close() return case os.IsNotExist(err): r.URL.Path = "/" // vue app 虚拟路由统一回 index.html n.fileServer.ServeHTTP(w, r) return default: http.Error(w, "not found", http.StatusNotFound) return } }