如何使用Go模板渲染CSS和JS文件

0vvn1miw  于 2023-09-28  发布在  Go
关注(0)|答案(3)|浏览(133)

我尝试使用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塞尔达尔的建议,我实现了以下代码:

已添加到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等共享该文件夹。

**EDIT 2:**看起来我的方法可能不是最好的,所以我尝试使用内置的FileServer。不过,我不太清楚该怎么做。

我加了这一行

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

registerRoutes,但它不工作。

    • 我试图在Go中实现类似于Flask的功能。这意味着根据访问的路径重定向到某些模板。我所说的模板是一个可以传递变量的.html文件。
    • 我加
fs := http.FileServer(http.Dir("static"))
mux.Handle("/static/", http.StripPrefix("/static", fs))

main.go中的main()函数。然后删除了mux.HandleFunc("/static/", staticHandler)staticHandler函数。

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

例如

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页呢?此外,我如何将这些变量传递给上面定义的处理函数?

EDIT6:

这个怎么样?
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"]

**编辑7:**不确定我是否应该在这一点上提出一个新的问题,但我会继续下去。

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

**EDIT 8:**我通过添加解决了我以前的编辑

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

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

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

如果是这样,我该怎么做呢?

yrefmtwq

yrefmtwq1#

你还必须“服务”JS和CSS文件。
模板将作为HTML页面呈现和发送。一旦HTML页面被加载,浏览器就会尝试使用页面中的链接加载CSS和JS文件。由于您的服务器不处理这些路由,因此浏览器无法加载它们。
我建议不要使用../static path,而是在HTML中使用/static,并使用加载CSS和JS文件并返回它们的处理程序将该路由挂载到路由器。您还必须设置响应的Content-Type,以便浏览器可以正确使用这些文件。

// Register the handler
mux.HandleFunc("/static", staticHandler)

func staticHandler(w http.ResponseWriter, r *http.Request) {
   // load the file using r.URL.Path, like /static/scripts/index.js"
   data,err:=ioutil.ReadFile(...)
   // Figure out file type:
   if strings.EndsWith("js") {
      w.Header.Set("Content-Type","text/javascript")  
   } else {
      w.Header.Set("Content-Type","text/css")
   }
   w.Write(data)
}
hwamh0ep

hwamh0ep2#

感谢@Burak塞尔达尔的指导,我修复了他的一些代码,并添加了一些东西来获得解决方案。
将此添加到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)
dzhpxtsq

dzhpxtsq3#

对我很有效关键点是静态处理程序的路由器,您需要确保为静态文件引用正确的绝对路径。这是:

dir结构

.
go.mod
go.sum
website/
├── main.go
└── static
    ├── css
    │   └── index.css
    ├── scripts
    │   └── index.js
    └── templates
        └── index.html

去跑步:

go run ./website/

main.go

var (
    staticDir    = getAbsDirPath() + "/static/"
    templatesDir = staticDir + "/templates"
    templates = template.Must(template.ParseFiles(
        templatesDir + "/index.html",
    ))
)

func getAbsDirPath() string {
    pwd, err := os.Getwd()
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }
    // my dir name is 'website'
    return pwd + "/website"
}

func indexHandler(w http.ResponseWriter, r *http.Request) {
    err := templates.ExecuteTemplate(w, "index.html", nil)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
    }
}

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")
    }
    // make sure you reference the correct absolute path
    data, err := ioutil.ReadFile(staticDir + path[1:])
    if err != nil {
        fmt.Print(err)
    }
    _, err = w.Write(data)
    if err != nil {
        fmt.Print(err)
    }
}

func main() {
    http.HandleFunc("/", indexHandler)
    // <link rel="stylesheet" href="../css/index.css">
    // <script src="../scripts/index.js" defer></script>
    http.HandleFunc("/scripts/", staticHandler)
    http.HandleFunc("/css/", staticHandler)
    log.Fatal(http.ListenAndServe(":80", nil))
}

首页渲染

静态文件详情

index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Index</title>
  <link rel="stylesheet" href="../css/index.css">
</head>
<body>

<h1>Welcome to Litong's homepage!</h1>

<script src="../scripts/index.js" defer></script>

</body>
</html>

index.js

let title = document.querySelector('h1')

title.onclick = function () {
  alert('Let\'s build a better world!')
}

index.css

h1 {
  width: auto;
  text-align: center;
}

相关问题