package main import ( "fmt" "io" "log" "net" "net/http" "net/http/httputil" "net/url" "strings" "sync" "time" ) // Backend结构体 var Backends []*Backend // 设置跨域请求 func SetCors(w http.ResponseWriter, r *http.Request) { w.Header().Set("Access-Control-Allow-Origin", "*") w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE") w.Header().Set("Access-Control-Allow-Headers", "*") w.Header().Set("Access-Control-Expose-Headers", "*") w.Header().Set("Access-Control-Allow-Credentials", "true") // 如果请求方法为 OPTIONS,直接返回 200 状态码 if r.Method == "OPTIONS" { w.WriteHeader(http.StatusOK) return } } // 存储路径的并发安全的Map var pathdict sync.Map = sync.Map{} func main() { // 将静态资源路径存储到pathdict pathdict.Store("/css", true) pathdict.Store("/fonts", true) pathdict.Store("/img", true) pathdict.Store("/js", true) pathdict.Store("/svg", true) pathdict.Store("/favicon.ico", true) rootDir := "../server" // 更改为你的根目录 vueBuild := "/opt/fusenpack-vue-created" apiURL, err := url.Parse("http://localhost:9900") if err != nil { panic(err) } mux := http.NewServeMux() // 获取并解析服务信息 results := GetZeroInfo(rootDir) var allRoutes map[string]bool = make(map[string]bool) for _, result := range results { fmt.Printf("FolderName: %s, Host: %s, Port: %d, PrefixRoute: %v\n", result.FolderName, result.Host, result.Port, result.PrefixRoute) var routes []string for k := range result.PrefixRoute { routes = append(routes, k) allRoutes[k] = true } // 根据获取的服务信息创建后端服务 Backends = append(Backends, NewBackend(mux, fmt.Sprintf("http://%s:%d", result.Host, result.Port), routes...)) } // 定义用于服务Vue dist文件夹的静态文件服务器 fs := http.FileServer(http.Dir(vueBuild)) indexHtmlPath := vueBuild + "/index.html" mux.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if strings.HasPrefix(r.URL.Path, "/api/") { // 对/api开头的请求进行反向代理 proxy := httputil.NewSingleHostReverseProxy(apiURL) proxy.ServeHTTP(w, r) return } else { // 根据请求路径判断是服务静态文件或者是返回index.html idx := strings.Index(r.URL.Path[1:], "/") var prefix string if idx != -1 { prefix = r.URL.Path[:idx+1] } else { prefix = r.URL.Path } if _, ok := pathdict.Load(prefix); ok { fs.ServeHTTP(w, r) } else { http.ServeFile(w, r, indexHtmlPath) } } })) ServerAddress := ":9900" log.Println("listen on ", ServerAddress) log.Fatal(http.ListenAndServe(ServerAddress, mux)) } // 后端服务的类型 type Backend struct { HttpAddress string Client *http.Client Handler http.HandlerFunc } func NewBackend(mux *http.ServeMux, httpAddress string, muxPaths ...string) *Backend { // 如果路径最后没有以'/'结尾,则添加'/' for i, muxPath := range muxPaths { if muxPath[len(muxPath)-1] != '/' { muxPath = muxPath + "/" muxPaths[i] = muxPath } } // 创建HTTP客户端,设置相关的超时参数和连接数限制 client := &http.Client{ Transport: &http.Transport{ DialContext: (&net.Dialer{ Timeout: 30 * time.Second, KeepAlive: 30 * time.Second, }).DialContext, ForceAttemptHTTP2: true, MaxIdleConns: 100, MaxIdleConnsPerHost: 100, IdleConnTimeout: 90 * time.Second, TLSHandshakeTimeout: 10 * time.Second, ExpectContinueTimeout: 1 * time.Second, }, } // 创建后端服务对象,包含地址和客户端 backend := &Backend{ HttpAddress: httpAddress, Client: client, } // 创建处理请求的函数 handleRequest := func(w http.ResponseWriter, r *http.Request) { // 解析目标URL,包含了查询参数 targetURL, err := url.Parse(httpAddress + r.URL.String()) if err != nil { http.Error(w, "Error parsing target URL", http.StatusInternalServerError) return } // 创建新的请求 proxyReq, err := http.NewRequest(r.Method, targetURL.String(), r.Body) if err != nil { http.Error(w, "Error creating proxy request", http.StatusInternalServerError) return } // 复制原始请求的 Header for key, values := range r.Header { for _, value := range values { proxyReq.Header.Add(key, value) } } // 设置 Content-Length 和 Content-Type proxyReq.ContentLength = r.ContentLength proxyReq.Header.Set("Content-Type", r.Header.Get("Content-Type")) // 发送请求 resp, err := backend.Client.Do(proxyReq) if err != nil { http.Error(w, "Error sending proxy request", http.StatusInternalServerError) return } defer resp.Body.Close() // 复制目标服务器的响应 Header for key, values := range resp.Header { for _, value := range values { w.Header().Add(key, value) } } // 转发目标服务器的响应状态码和主体 w.WriteHeader(resp.StatusCode) _, err = io.Copy(w, resp.Body) if err != nil { http.Error(w, "Error copying proxy response", http.StatusInternalServerError) return } } // 为每个路径注册处理函数 for _, muxPath := range muxPaths { mux.HandleFunc(muxPath, handleRequest) } // 返回后端服务对象 return backend }