首页 > 解决方案 > 如何使用 Go 模板渲染 CSS 和 JS 文件

问题描述

我正在尝试使用 Go 在我的 html 模板中包含 CSS 和 JS 文件。

这是我的代码

main.go

package main

import (
    "fmt"
    "net/http"
)

func main() {
    var mux = http.NewServeMux()
    registerRoutes(mux)
    httpServer := http.Server{
        Addr:    ":3000",
        Handler: mux,
    }
    err := httpServer.ListenAndServe()
    if err != nil {
        fmt.Print(err)
    }
}

routes.go

package main

import "net/http"

func registerRoutes(mux *http.ServeMux) {
    mux.HandleFunc("/", index)
    mux.HandleFunc("/faq", faq)
}

handlers.go

package main

import (
    "fmt"
    "html/template"
    "net/http"
)

func index(w http.ResponseWriter, r *http.Request) {
    tmpl, err := template.ParseFiles("templates/index.html")
    if err != nil {
        fmt.Print(err)
    }
    err = tmpl.Execute(w, nil)
    if err != nil {
        fmt.Print(err)
    }
}

func faq(w http.ResponseWriter, r *http.Request) {
    tmpl, err := template.ParseFiles("templates/faq.html")
    if err != nil {
        fmt.Print(err)
    }
    err = tmpl.Execute(w, nil)
    if err != nil {
        fmt.Print(err)
    }
}

index.html

<!DOCTYPE html>
<html lang="en" dir="ltr">
    <head>
        <meta charset="utf-8">
        <title>Index</title>
        <link href="../static/stylesheets/main.css" type="text/css" rel="stylesheet">
        <script type="text/javascript" src="../static/scripts/index.js"></script>
    </head>
    <body>
        <h1>Test</h1>
    </body>
</html>

渲染 HTML 是可行的,但它不包括 CSS 或 JS 文件。我怎样才能让它识别它们?

谢谢。


编辑:正如@Burak Serdar 所建议的,我已经实现了以下代码:

将此添加到handlers.go

func staticHandler(w http.ResponseWriter, r *http.Request) {
   // load the file using r.URL.Path, like /static/scripts/index.js"
   path := r.URL.Path
   data, err := ioutil.ReadFile(path)
   if err != nil {
        fmt.Print(err)
    }
   if strings.HasSuffix(path, "js") {
      w.Header().Set("Content-Type","text/javascript")
   } else {
      w.Header().Set("Content-Type","text/css")
   }
   _, err = w.Write(data)
   if err != nil {
        fmt.Print(err)
    }
}

将此添加到routes.go

mux.HandleFunc("/static", staticHandler)

但是,它仍然不起作用。

也许我应该注意,static/并且templates/它们在同一个文件夹中,并且它们与main.go等共享文件夹。


EDIT2:看来我的方法可能不是最好的,所以我正在尝试使用内置的FileServer. 但是,我不知道该怎么做。

我添加了这一行

http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("C:/Users/x/Documents/Coding/Go/hello_world/"))))

到,registerRoutes但它不工作。


EDIT3:也许我应该明确我想要实现的目标。我正在尝试在 Go 中实现类似 Flask 的功能。这意味着根据访问的路径重定向到某些模板。我所说的模板是.html指我可以将变量传递给的文件。


EDIT4:我想我已经实现了我想要的。我添加了

fs := http.FileServer(http.Dir("static"))
mux.Handle("/static/", http.StripPrefix("/static", fs))

到我的main()功能main.go。然后去掉mux.HandleFunc("/static/", staticHandler)staticHandler函数。


EDIT5:假设这是一个好方法,我最后关心的是如何处理缓存。很明显,每次呈现页面时我都会解析文件tmpl, err := template.ParseFiles("templates/index.html")等。因此,我想也许我可以添加一个函数来加载这些文件并返回模板,然后在 main 中调用这个函数并将变量传递给处理程序。这是一个好主意吗?你会怎么做呢?这是否意味着我的文件只有在我重新启动网络服务器时才会更新?

例如

func initTemplates() (*template.Template, *template.Template) {
    indexTemplate := template.Must(template.ParseFiles("templates/index.html"))
    faqTemplate := template.Must(template.ParseFiles("templates/faq.html"))
    return indexTemplate, faqTemplate
}

func main() {
    var mux = http.NewServeMux()
    fs := http.FileServer(http.Dir("static"))
    mux.Handle("/static/", http.StripPrefix("/static", fs))
    indexTemplate, faqTemplate := initTemplates()
    ...
}

我的问题是在我的网站上的每个页面都有一个像这样的变量似乎很奇怪。如果我想要 100 页怎么办?此外,我什至如何将这些变量传递给上面定义的处理函数?


编辑6:

这个怎么样?

main.go

var templates map[string]*template.Template

func init() {
    if templates == nil {
        templates = make(map[string]*template.Template)
    }

    templates["index.html"] = template.Must(template.ParseFiles("templates/index.html"))
    templates["faq.html"] = template.Must(template.ParseFiles("templates/faq.html"))
}

func main() {
    var mux = http.NewServeMux()
    fs := http.FileServer(http.Dir("static"))
    mux.Handle("/static/", http.StripPrefix("/static", fs))
    registerRoutes(mux)
    httpServer := http.Server{
        Addr:    ":3000",
        Handler: mux,
    }
    err := httpServer.ListenAndServe()
    if err != nil {
        fmt.Print(err)
    }
}

然后在handlers.go我使用tmpl := templates["index.html"]


EDIT7:不确定我是否应该在这一点上提出一个新问题,但我会继续前进。

我在尝试服务资源时遇到了问题/purchase/license。现在服务器正在查看/purchase/static/stylesheets/main.css该页面。我该如何解决这个问题?


EDIT8:我通过添加解决了我以前的编辑

mux.Handle("/purchase/static/", http.StripPrefix("/purchase/static", fs))

main(). 有没有更好、更可扩展的方法来解决这个问题?如果我有数百个/x/y,我真的需要为每个添加一个x吗?我可以使用正则表达式或其他东西来添加这样的通配符吗?

mux.Handle("*/static/", http.StripPrefix("*/static", fs))

如果是这样,我将如何做到这一点?

标签: go

解决方案


感谢@Burak Serdar 的指导,我修复了他的一些代码并添加了一些东西来获得解决方案。

将此添加到handlers.go

func staticHandler(w http.ResponseWriter, r *http.Request) {
   path := r.URL.Path
   if strings.HasSuffix(path, "js") {
      w.Header().Set("Content-Type","text/javascript")
   } else {
      w.Header().Set("Content-Type","text/css")
   }
   data, err := ioutil.ReadFile(path[1:])
   if err != nil {
        fmt.Print(err)
    }
   _, err = w.Write(data)
   if err != nil {
        fmt.Print(err)
   }
}

将此添加到routes.go

mux.HandleFunc("/static/", staticHandler)

推荐阅读