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

4 回复

我还没有使用过templ,但我知道它备受推崇。我刚刚查阅了文档,它看起来非常棒!

更多关于Golang中返回HTML、CSS和JS的最佳方式是什么的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


我发现了这个。值得使用吗? 🙂

GitHub - a-h/templ: 一个用于在 Go 中编写 HTML 用户界面的语言。

一个用于在 Go 中编写 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 攻击,而模板函数可以处理特殊的转义需求。

回到顶部