2023-07-11 05:07:44 +00:00
|
|
|
|
package main
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"fmt"
|
|
|
|
|
"io"
|
|
|
|
|
"log"
|
|
|
|
|
"net"
|
|
|
|
|
"net/http"
|
2023-07-11 08:50:18 +00:00
|
|
|
|
"net/http/httputil"
|
2023-07-11 05:07:44 +00:00
|
|
|
|
"net/url"
|
2023-07-11 08:50:18 +00:00
|
|
|
|
"strings"
|
2023-07-11 05:07:44 +00:00
|
|
|
|
"time"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
var Backends []*Backend
|
|
|
|
|
|
2023-07-11 10:48:22 +00:00
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-11 05:07:44 +00:00
|
|
|
|
func main() {
|
|
|
|
|
rootDir := "../server" // Change this to your root directory
|
2023-07-11 11:43:46 +00:00
|
|
|
|
vueBuild := "/home/eson/workspace/fusenpack-vue-created"
|
2023-07-11 08:50:18 +00:00
|
|
|
|
apiURL, err := url.Parse("http://localhost:9900")
|
|
|
|
|
if err != nil {
|
|
|
|
|
panic(err)
|
|
|
|
|
}
|
2023-07-11 05:07:44 +00:00
|
|
|
|
|
|
|
|
|
mux := http.NewServeMux()
|
|
|
|
|
|
|
|
|
|
results := GetZeroInfo(rootDir)
|
2023-07-11 08:50:18 +00:00
|
|
|
|
|
|
|
|
|
var allRoutes map[string]bool = make(map[string]bool)
|
2023-07-11 05:07:44 +00:00
|
|
|
|
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)
|
2023-07-11 08:50:18 +00:00
|
|
|
|
allRoutes[k] = true
|
2023-07-11 05:07:44 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Backends = append(Backends,
|
|
|
|
|
NewBackend(mux,
|
|
|
|
|
fmt.Sprintf("http://%s:%d", result.Host, result.Port),
|
|
|
|
|
routes...))
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-11 08:50:18 +00:00
|
|
|
|
// Define the static file server that serves the Vue dist folder
|
|
|
|
|
fs := http.FileServer(http.Dir(vueBuild))
|
2023-07-11 10:48:22 +00:00
|
|
|
|
indexHtmlPath := vueBuild + "/index.html"
|
|
|
|
|
mux.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
2023-07-11 08:50:18 +00:00
|
|
|
|
var prefix string
|
|
|
|
|
idx := strings.Index(r.URL.Path[1:], "/")
|
|
|
|
|
if idx == -1 {
|
|
|
|
|
prefix = r.URL.Path
|
|
|
|
|
} else {
|
|
|
|
|
prefix = r.URL.Path[:idx]
|
|
|
|
|
}
|
2023-07-11 10:48:22 +00:00
|
|
|
|
|
2023-07-11 08:50:18 +00:00
|
|
|
|
// log.Println(r.URL.Path, prefix)
|
|
|
|
|
if _, ok := allRoutes[prefix]; ok {
|
|
|
|
|
proxy := httputil.NewSingleHostReverseProxy(apiURL)
|
|
|
|
|
proxy.ServeHTTP(w, r)
|
|
|
|
|
} else {
|
|
|
|
|
// fs.ServeHTTP(w, r)
|
|
|
|
|
if strings.HasPrefix(prefix, "/type") {
|
2023-07-11 10:48:22 +00:00
|
|
|
|
http.ServeFile(w, r, indexHtmlPath)
|
2023-07-11 08:50:18 +00:00
|
|
|
|
} else if strings.HasPrefix(prefix, "/dt-") {
|
2023-07-11 10:48:22 +00:00
|
|
|
|
http.ServeFile(w, r, indexHtmlPath)
|
2023-07-11 08:50:18 +00:00
|
|
|
|
} else {
|
|
|
|
|
fs.ServeHTTP(w, r)
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-07-11 10:48:22 +00:00
|
|
|
|
}))
|
2023-07-11 08:50:18 +00:00
|
|
|
|
|
2023-07-11 05:07:44 +00:00
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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) {
|
|
|
|
|
targetURL, err := url.Parse(httpAddress + r.URL.Path)
|
|
|
|
|
if err != nil {
|
|
|
|
|
http.Error(w, "Error parsing target URL", http.StatusInternalServerError)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-11 11:43:46 +00:00
|
|
|
|
// hasBridge := strings.Contains(r.Header.Get("Access-Control-Request-Headers"), "bridge")
|
2023-07-11 10:48:22 +00:00
|
|
|
|
|
2023-07-11 05:07:44 +00:00
|
|
|
|
// 解析目标URL时已经包含了查询参数
|
|
|
|
|
targetURL.RawQuery = r.URL.RawQuery
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-11 11:43:46 +00:00
|
|
|
|
// if hasBridge {
|
|
|
|
|
// w.Header().Add("Access-Control-Allow-Headers", "Bridge")
|
|
|
|
|
// }
|
2023-07-11 10:48:22 +00:00
|
|
|
|
|
2023-07-11 05:07:44 +00:00
|
|
|
|
// 转发目标服务器的响应状态码和主体
|
|
|
|
|
w.WriteHeader(resp.StatusCode)
|
|
|
|
|
_, err = io.Copy(w, resp.Body)
|
|
|
|
|
if err != nil {
|
|
|
|
|
http.Error(w, "Error copying proxy response", http.StatusInternalServerError)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-07-11 11:43:46 +00:00
|
|
|
|
|
2023-07-11 05:07:44 +00:00
|
|
|
|
for _, muxPath := range muxPaths {
|
|
|
|
|
mux.HandleFunc(muxPath, handleRequest)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return backend
|
|
|
|
|
}
|