当提供静态文件时,遇到了Golang错误。

huangapple go评论97阅读模式
英文:

golang error when serving static files

问题

我无法解决这个在执行模板时出现的Go语言错误:

panic: open templates/*.html: 系统找不到指定的路径。

另一个问题是我的public文件夹无法提供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
pkg
pub
   css
     home.css
   js
src
   github.com
        gorila/mux
templates
        index.html

我的GOROOT指向包含binpkgsrc文件夹的project文件夹。

当我将templates文件夹放在src之外时,它可以正常工作,但我认为这不正确,一切都应该在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文件夹的问题。

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

英文:

I can't figure out this error in go lang when executing a template

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

another problem is that my public folder can't be served from css and I don't know why.

code:

package main

import (
	&quot;net/http&quot;
	&quot;github.com/gorilla/mux&quot;
	&quot;html/template&quot;
	&quot;log&quot;
)

var tpl *template.Template

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

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

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

my folder is like that:

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

my GOROOT is pointing to the folder project which contains the bin pkg src

when I make the templates folder outside src it works fine but I thinks that's not right everything must be in src right ?

index.html

    &lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
&lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot;&gt;
    &lt;title&gt;test&lt;/title&gt;
    &lt;link href=&quot;../public/css/home.css&quot; type=&quot;text/css&quot; rel=&quot;stylesheet&quot; /&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;h1&gt;welcome! hi&lt;/h1&gt;
&lt;/body&gt;
&lt;/html&gt;

here i can't serve the css

UPDATE::

the first problem is solved of the templates folder .

but I am still cannot solve the second issue

答案1

得分: 3

我个人认为标准的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的好做法。

英文:

I personally find the standard http library very good and simple for such tasks. However, if you insist on Gorilla's mux here is the problem I found in your code:

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

On one hand you are using http.Handle to serve static files but on the other hand you're giving r to http.ListenAndServe.

To fix this just change that line into:

r.PathPrefix(&quot;/public/&quot;).Handler(
       http.StripPrefix(&quot;/public/&quot;,
           http.FileServer(http.Dir(&quot;/pub/&quot;))))

If I may, I would like to suggest using flag to set a different path to the templates directory and to the public directory so it would be easy to deploy and run your server.

In other words, instead of hardcoding the path to these directories you can run:

./myserver -templates=/loca/templates -public=/home/root/public

To do that just add the following:

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

    flag.Parse()
    tpl = template.Must(template.ParseGlob(templatesPath+&quot;/*.html&quot;))
    r.HandleFunc(&quot;/&quot;, handlerHomeTemplates(tpl))
    r.PathPrefix(&quot;/public/&quot;).Handler(http.StripPrefix(&quot;/public/&quot;, 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, &quot;index.html&quot;, nil)
        if err != nil {
            ...
        }
    })
}

Even thought the init function is a good place to do part of it, I think it's a good practice to avoid it unless it's needed. That's why I did all the initialization in the main function and used handlerHomeTemplates to return a new http.HandleFunc that uses templatesPath.

huangapple
  • 本文由 发表于 2017年8月27日 05:03:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/45899656.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定