【问题标题】:golang error when serving static files提供静态文件时出现golang错误
【发布时间】:2017-08-27 19:06:28
【问题描述】:

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

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

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

代码:

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
包
酒馆
   css
     主页.css
   js
源代码
   github.com
        大猩猩/多路复用器
模板
        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

更新::

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

但我仍然无法解决第二个问题

【问题讨论】:

  • templates 文件夹只需要靠近您在构建二进制文件时创建的二进制文件。 src 文件夹仅对源文件是必需的。因为模板是在运行时加载的
  • 所以你的意思是当我去生产时我将使用 bin 文件夹而不是 src 文件夹?所以我很抱歉地问,那么 src 在生产中是用来做什么的?我的意思是如果有人使用我的代码,他将如何使用我的代码?来自包裹?
  • 所以你的意思是我从src取出文件夹并将其放在project文件夹下,然后将parseGlobtemplates/*.html更改为src/templates/*.html
  • templates/*.html 与您启动二进制文件的位置相关,它与 golang 设置的其余部分无关。如果您要构建二进制文件并将其保留在 bin 中,那么您希望将模板文件夹复制到那里。如果你要将它放在 pkg 中,那么你需要在那里有模板。
  • 我也将它用于公共文件夹吗?我把 public 和 template 文件夹都放在了 src 之外,我把它们放在 bin 旁边的项目文件夹下?

标签: go go-templates fileserver go-html-template gopath


【解决方案1】:

我个人认为标准的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 为模板目录和公共目录设置不同的路径,以便于部署和运行您的服务器。

换句话说,您可以运行这些目录的路径,而不是硬编码:

./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 返回一个使用 templatesPath 的新 http.HandleFunc

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-03-13
    • 1970-01-01
    • 2019-04-12
    • 2019-01-09
    • 2015-02-28
    • 2017-09-04
    • 2018-12-05
    • 2015-11-20
    相关资源
    最近更新 更多