提供静态文件时出现 golang 错误

golang error when serving static files

在执行模板时,我无法在go lang中找出这个错误

panic: open templates/*.html: The system cannot find the path specified.

另一个问题是 css 无法提供我的 public 文件夹,我不知道为什么。

代码:

package main

import (
    "net/http"
    "github.com/gorilla/mux"
    "html/template"
    "log"
)

var tpl *template.Template

func init() {
    tpl = template.Must(template.ParseGlob("templates/*.html"))
}

func main() {
    r := mux.NewRouter()
    r.HandleFunc("/",home)
    http.Handle("/public/", http.StripPrefix("/public/", 
    http.FileServer(http.Dir("/pub"))))
    http.ListenAndServe(":8080", r)
}

func home(writer http.ResponseWriter, request *http.Request) {
    err := tpl.ExecuteTemplate(writer, "index.html", nil)
    if err != nil {
        log.Println(err)
        http.Error(writer, "Internal server error", http.StatusInternalServerError)
    }
}

我的文件夹是这样的:

bin
pkg
pub
   css
     home.css
   js
src
   github.com
        gorila/mux
templates
        index.html

我的 GOROOT 指向文件夹 project,其中包含 bin pkg src

当我在 src 之外创建 templates 文件夹时,它工作正常,但我认为这是不正确的,所有内容都必须在 src 中,对吗?

index.html

    <!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>test</title>
    <link href="../public/css/home.css" type="text/css" rel="stylesheet" />
</head>
<body>
<h1>welcome! hi</h1>
</body>
</html>

这里我不能提供 css

更新::

模板文件夹的第一个问题解决了。

但是我还是解决不了第二个问题

我个人认为标准 http 库对于此类任务非常好且简单。但是,如果您坚持使用 Gorilla 的 mux,这就是我在您的代码中发现的问题:

func main() {
    ...
    http.Handle("/public/", http.StripPrefix("/public/", http.FileServer(http.Dir("/pub"))))
    http.ListenAndServe(":8080", r)
}

一方面,您使用 http.Handle 提供静态文件,但另一方面,您将 r 提供给 http.ListenAndServe

要解决此问题,只需将该行更改为:

r.PathPrefix("/public/").Handler(
       http.StripPrefix("/public/",
           http.FileServer(http.Dir("/pub/"))))

如果可以的话,我想建议使用 flag 为模板目录和 public 目录设置不同的路径,以便于部署和 运行 你的服务器。

换句话说,您可以 运行:

而不是对这些目录的路径进行硬编码
./myserver -templates=/loca/templates -public=/home/root/public

为此只需添加以下内容:

import "flag"
....
func main() {
    var tpl *template.Template
    var templatesPath, publicPath string
    flag.StringVar(&templatesPath, "templates", "./templates", "Path to templates")
    flag.StringVar(&publicPath, "public", "./public", "Path to public")

    flag.Parse()
    tpl = template.Must(template.ParseGlob(templatesPath+"/*.html"))
    r.HandleFunc("/", handlerHomeTemplates(tpl))
    r.PathPrefix("/public/").Handler(http.StripPrefix("/public/", http.FileServer(http.Dir(publicPath))))
    ...
}

func handlerHomeTemplates(tpl *template.Template) http.HandlerFunc {
    return http.HandlerFunc(func((writer http.ResponseWriter, request *http.Request) {
        err := tpl.ExecuteTemplate(writer, "index.html", nil)
        if err != nil {
            ...
        }
    })
}

虽然认为 init 函数是执行其中一部分的好地方,但我认为除非需要,否则最好避免使用它。这就是为什么我在 main 函数中进行所有初始化并使用 handlerHomeTemplates 到 return 一个使用 templatesPath.

的新 http.HandleFunc