用于 React 的 HTTP 服务器,Angular,等等
Go HTTP Server for React, Angular, etc
我在 GO 中为静态文件创建了这个小型 HTTP 服务器:
func wrapHandler(h http.Handler) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
h.ServeHTTP(srw, r)
log.Printf("GET %s", r.RequestURI)
}
}
func main() {
http.HandleFunc("/", wrapHandler(
http.FileServer(http.Dir("/static"))
))
if err := http.ListenAndServe(":8080", nil); err != nil {
panic(err)
}
}
它与 React 和 Angular dist
文件完美配合(在转换它们之后)。但是,如果我已经选择了一条路线,例如http://example.org:8080/customers 并在浏览器中单击刷新 我收到 404 页面未找到。这是我的代码失败的唯一情况。
发生这种情况是因为在 React 上 Angular index.html
充当前端控制器并可以处理路由。但是,为了使其正常工作,我需要在内部将所有 not found 请求重定向到 index.html.
因为是 angular/react 处理路由,所以我不想为 angular/react 中创建的每个路由创建一个 http.HandleFunc
。我想要类似于 express
的东西:
app.use(express.static(path.join(__dirname, 'static')));
app.use("*",function(req,res){
res.sendFile(path.join(__dirname, 'static/index.html'));
});
或 NGINX:
try_files $uri $uri/ index.html;
关于如何在 go 中执行此操作的任何线索?
了解 Go 的 http 包如何处理路由匹配很重要,因为它与其他 languages/frameworks 有点不同。 HandleFunc
在后台使用 ServeMux 并且(来自 docs):
ServeMux is an HTTP request multiplexer. It matches the URL of each incoming request against a list of registered patterns and calls the handler for the pattern that most closely matches the URL. [emphasis mine]
鉴于此行为,我建议为每个静态文件夹创建显式处理程序(例如 css/
、js/
),或将所有文件夹放在一个静态子文件夹中,然后用您的index.html
文件用于所有其他请求(使用根路由 (/
))。这是可行的,因为路由前缀为 /css/
或 /js/
的请求将更接近地匹配适当的静态处理程序路由,而所有其他请求不会因此仅最接近地匹配根路由。您只需要确保不要在前端创建冲突的路由。
这样,任何对 CSS/JS/image 资产的明确请求都将通过提供静态目录来处理,所有其他请求都将通过您的 React 应用程序得到响应。
这是一个示例(为简单起见,省略了您的 wrapHandler
):
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, "static/index.html")
})
http.Handle("/js/", http.FileServer(http.Dir("static")))
http.Handle("/css/", http.FileServer(http.Dir("static")))
if err := http.ListenAndServe(":8080", nil); err != nil {
panic(err)
}
}
或者如果你想更明确一点:
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, "static/index.html")
})
jsFs := http.FileServer(http.Dir("static/js"))
http.Handle("/js/", http.StripPrefix("/js", jsFs))
cssFs := http.FileServer(http.Dir("static/css"))
http.Handle("/css/", http.StripPrefix("/css", cssFs))
if err := http.ListenAndServe(":8080", nil); err != nil {
panic(err)
}
}
我的网站的工作方式几乎相同(使用 Vue 而不是 React)。
一个改进
如上所述,您可以考虑将所有静态资源放在当前 static/
文件夹的子文件夹中。考虑像这样构建文件:
public/
index.html
static/
css/
js/
img/
这是构建 React 应用程序的默认文件结构(但 public
默认称为 build
)。
这将使您能够以更精简的方式使用上述方法,因为您只需要一个文件服务器处理程序来处理所有静态资产。然后你可以使用下面的代码:
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, "public/index.html")
})
fs := http.FileServer(http.Dir("public/static/"))
http.Handle("/static/", http.StripPrefix("/static", fs))
if err := http.ListenAndServe(":8080", nil); err != nil {
panic(err)
}
}
我在 GO 中为静态文件创建了这个小型 HTTP 服务器:
func wrapHandler(h http.Handler) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
h.ServeHTTP(srw, r)
log.Printf("GET %s", r.RequestURI)
}
}
func main() {
http.HandleFunc("/", wrapHandler(
http.FileServer(http.Dir("/static"))
))
if err := http.ListenAndServe(":8080", nil); err != nil {
panic(err)
}
}
它与 React 和 Angular dist
文件完美配合(在转换它们之后)。但是,如果我已经选择了一条路线,例如http://example.org:8080/customers 并在浏览器中单击刷新 我收到 404 页面未找到。这是我的代码失败的唯一情况。
发生这种情况是因为在 React 上 Angular index.html
充当前端控制器并可以处理路由。但是,为了使其正常工作,我需要在内部将所有 not found 请求重定向到 index.html.
因为是 angular/react 处理路由,所以我不想为 angular/react 中创建的每个路由创建一个 http.HandleFunc
。我想要类似于 express
的东西:
app.use(express.static(path.join(__dirname, 'static')));
app.use("*",function(req,res){
res.sendFile(path.join(__dirname, 'static/index.html'));
});
或 NGINX:
try_files $uri $uri/ index.html;
关于如何在 go 中执行此操作的任何线索?
了解 Go 的 http 包如何处理路由匹配很重要,因为它与其他 languages/frameworks 有点不同。 HandleFunc
在后台使用 ServeMux 并且(来自 docs):
ServeMux is an HTTP request multiplexer. It matches the URL of each incoming request against a list of registered patterns and calls the handler for the pattern that most closely matches the URL. [emphasis mine]
鉴于此行为,我建议为每个静态文件夹创建显式处理程序(例如 css/
、js/
),或将所有文件夹放在一个静态子文件夹中,然后用您的index.html
文件用于所有其他请求(使用根路由 (/
))。这是可行的,因为路由前缀为 /css/
或 /js/
的请求将更接近地匹配适当的静态处理程序路由,而所有其他请求不会因此仅最接近地匹配根路由。您只需要确保不要在前端创建冲突的路由。
这样,任何对 CSS/JS/image 资产的明确请求都将通过提供静态目录来处理,所有其他请求都将通过您的 React 应用程序得到响应。
这是一个示例(为简单起见,省略了您的 wrapHandler
):
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, "static/index.html")
})
http.Handle("/js/", http.FileServer(http.Dir("static")))
http.Handle("/css/", http.FileServer(http.Dir("static")))
if err := http.ListenAndServe(":8080", nil); err != nil {
panic(err)
}
}
或者如果你想更明确一点:
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, "static/index.html")
})
jsFs := http.FileServer(http.Dir("static/js"))
http.Handle("/js/", http.StripPrefix("/js", jsFs))
cssFs := http.FileServer(http.Dir("static/css"))
http.Handle("/css/", http.StripPrefix("/css", cssFs))
if err := http.ListenAndServe(":8080", nil); err != nil {
panic(err)
}
}
我的网站的工作方式几乎相同(使用 Vue 而不是 React)。
一个改进
如上所述,您可以考虑将所有静态资源放在当前 static/
文件夹的子文件夹中。考虑像这样构建文件:
public/
index.html
static/
css/
js/
img/
这是构建 React 应用程序的默认文件结构(但 public
默认称为 build
)。
这将使您能够以更精简的方式使用上述方法,因为您只需要一个文件服务器处理程序来处理所有静态资产。然后你可以使用下面的代码:
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, "public/index.html")
})
fs := http.FileServer(http.Dir("public/static/"))
http.Handle("/static/", http.StripPrefix("/static", fs))
if err := http.ListenAndServe(":8080", nil); err != nil {
panic(err)
}
}