Golang中返回HTML、CSS和JS的最佳方式是什么
Golang中返回HTML、CSS和JS的最佳方式是什么 我需要一个服务器端渲染的端点。
我目前在一个模板中包含了完整的HTML,以及内联的CSS和JS。
这种方式非常笨拙,而且我已经不得不拆分转义语法来启用反引号。不过它确实能工作!👍
我曾尝试将其拆分为三个不同的模板再进行组合。但这失败了: 有时看起来效果不错,但随后JavaScript在浏览器中就无法运行。
我相信只要多花些功夫,我总能解决这个问题,但也许有人一直在做这件事,并且找到了一个非常简单的方法?🙂
问题是: 在Go中,你如何管理那些需要进行服务器端渲染的复杂模板? 我希望JavaScript尽可能“自然”,因为我同时也需要开发它。 我希望最终输出是一个内联的HTML文件。
对于较长的文件,AI处理起来非常困难。 它似乎会被语法搞糊涂,无法正确处理。🤖🤯
data := TemplateData{
BaseURL: baseUrl,
SessionToken: sessionToken,
Id: idParam,
}
w.Header().Set("Content-Type", "text/html; charset=utf-8")
if err := tmpl.Execute(w, data); err != nil {
http.Error(w, "Failed to render page", http.StatusInternalServerError)
return
}
}
// Data structure for the template
type TemplateData struct {
BaseURL string
SessionToken string
Id string
}
// Global template variable
var tmpl = template.Must(template.New("index").Parse(`<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Custom LLM Persona - Anam Integration</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 20px;
background-color: #f5f5f5;
}
// This is one issue. Escaping Syntax.
formData.append("audio", audioBlob, ` + "`audio_${Date.now()}.ogg`" + `);
更多关于Golang中返回HTML、CSS和JS的最佳方式是什么的实战教程也可以访问 https://www.itying.com/category-94-b0.html
我还没有使用过templ,但我知道它备受推崇。我刚刚查阅了文档,它看起来非常棒!
更多关于Golang中返回HTML、CSS和JS的最佳方式是什么的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
对于大型字符串常量,我肯定会使用嵌入文件系统。在你的源代码中创建一个名为 template.html 的文件。将你所有的模板代码放在里面(无需转义),然后使用:
//go:embed template.html
var tmplStr string
这将在构建时包含 HTML 文件的内容,因此你最终仍然只会得到一个可执行文件作为输出,并且变量中包含字符串内容,就像你直接将其写为字符串字面量一样。
这样做的好处包括:更好的格式、更清晰的代码分离、编辑模板时能获得语法高亮,并且没有转义问题。
对于复杂模板的服务器端渲染,推荐使用 html/template 包的多模板组合功能。以下是具体实现方案:
package main
import (
"html/template"
"net/http"
)
// 定义模板数据结构
type TemplateData struct {
BaseURL string
SessionToken string
Id string
Title string
}
// 使用 ParseFiles 或 ParseGlob 加载多个模板文件
var tmpl = template.Must(template.ParseFiles(
"templates/base.html",
"templates/head.html",
"templates/body.html",
"templates/scripts.html",
))
func handler(w http.ResponseWriter, r *http.Request) {
data := TemplateData{
BaseURL: "https://example.com",
SessionToken: "abc123",
Id: "user456",
Title: "Custom LLM Persona",
}
w.Header().Set("Content-Type", "text/html; charset=utf-8")
// 执行主模板
if err := tmpl.ExecuteTemplate(w, "base.html", data); err != nil {
http.Error(w, "Failed to render page", http.StatusInternalServerError)
return
}
}
模板文件结构示例:
templates/base.html:
{{define "base.html"}}
<!DOCTYPE html>
<html lang="en">
{{template "head.html" .}}
{{template "body.html" .}}
</html>
{{end}}
templates/head.html:
{{define "head.html"}}
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{.Title}}</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 20px;
background-color: #f5f5f5;
}
/* 更多CSS样式 */
</style>
</head>
{{end}}
templates/scripts.html:
{{define "scripts.html"}}
<script>
// 使用 template.JS 避免转义问题
const baseURL = {{.BaseURL | js}};
const sessionToken = {{.SessionToken | js}};
// JavaScript 代码保持自然格式
function uploadAudio(audioBlob) {
const formData = new FormData();
formData.append("audio", audioBlob, `audio_${Date.now()}.ogg`);
// 更多逻辑
}
</script>
{{end}}
处理 JavaScript 转义问题的专业方案:
// 自定义模板函数处理 JavaScript
func init() {
tmpl = tmpl.Funcs(template.FuncMap{
"safeJS": func(s string) template.JS {
return template.JS(s)
},
})
}
// 在模板中使用
const config = {{safeJS `{"debug": true, "apiUrl": "`}}{{.BaseURL}}{{safeJS `"}`}};
内联资源的高级处理:
import "embed"
//go:embed templates/* static/*
var fs embed.FS
// 使用 embed.FS 嵌入资源
var tmpl = template.Must(template.ParseFS(fs,
"templates/*.html",
"static/css/*.css",
"static/js/*.js",
))
// CSS 和 JS 作为独立模板
{{define "styles.css"}}
/* 完整的CSS文件内容 */
{{end}}
{{define "app.js"}}
// 完整的JavaScript文件内容
{{end}}
最终的内联输出通过模板组合自动生成:
// 渲染为单个HTML文件
func renderInline(w http.ResponseWriter, data TemplateData) error {
return tmpl.ExecuteTemplate(w, "base.html", data)
}
这个方案保持 JavaScript 的自然语法,通过模板组合管理复杂度,同时生成内联的 HTML 输出。html/template 的自动上下文感知转义能防止 XSS 攻击,而模板函数可以处理特殊的转义需求。

