执行多个模板的条件判断

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

Execute multiple templates conditionally

问题

我有一个包含两个视图的网页,一个是匿名用户视图,另一个是管理员用户视图。我想要只为管理员用户显示一个导航栏,其他内容对于两种用户类型都保持不变。

这是我目前尝试过的代码:

main.go

package main

import (
	"log"
	"net/http"
	"text/template"

	"github.com/julienschmidt/httprouter"
)

func BasicAuth(h httprouter.Handle, requiredUser, requiredPassword string) httprouter.Handle {
	return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
		// 获取基本身份验证凭据
		user, password, hasAuth := r.BasicAuth()

		if hasAuth && user == requiredUser && password == requiredPassword {
			// 将请求委托给给定的处理函数
			h(w, r, ps)
		} else {
			// 否则要求进行基本身份验证
			w.Header().Set("WWW-Authenticate", "Basic realm=Restricted")
			http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
		}
	}
}

func Anonymous(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	t, err := template.ParseFiles("index.html")
	if err != nil {
		log.Fatalln(err)
	}
	err = t.Execute(w, map[string]string{"Name": "Anonymous"})
	if err != nil {
		log.Fatalln(err)
	}
}

func Admin(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	t, err := template.ParseFiles("index.html", "admin.html")
	if err != nil {
		log.Fatalln(err)
	}
	err = t.Execute(w, map[string]string{"Name": "Admin"})
	if err != nil {
		log.Fatalln(err)
	}
}

func main() {
	user := "admin"
	pass := "1234"

	router := httprouter.New()
	router.GET("/", Anonymous)
	router.GET("/admin/", BasicAuth(Admin, user, pass))

	log.Fatal(http.ListenAndServe(":8080", router))
}

index.html

<!DOCTYPE html>
<html lang="en">
	<head>
		<meta name="viewport" content="width=device-width, initial-scale=1.0">
		<title>{{ .Name }}</title>
		<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/css/bootstrap.min.css" rel="stylesheet">
		<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/js/bootstrap.bundle.min.js"></script>
		<script src="https://code.jquery.com/jquery-3.6.4.min.js"></script>
		<script>
			function counter() {
				document.getElementById("x").innerHTML = "x: " + document.querySelectorAll('.x').length;
				document.getElementById("y").innerHTML = "y: " + document.querySelectorAll('.y').length;
				document.getElementById("z").innerHTML = "z: " + document.querySelectorAll('.z').length;
			}
		</script>
	</head>
	<body onload="counter()">
		{{ template "dashboard" }}
		<nav class="navbar fixed-bottom">
			<div class="container-fluid nav-justified">
				<span id="x" class="navbar-brand nav-item"></span>
				<span id="y" class="navbar-brand nav-item"></span>
				<span id="z" class="navbar-brand nav-item"></span>
			</div>
		</nav>
	</body>
</html>

admin.html

{{ define "dashboard" }}
<nav class="navbar">
	<div class="container-fluid nav-justified">
		<span class="nav-item">
			<a class="navbar-brand" href="/a">a</a>
		</span>
		<span class="nav-item">
			<a class="navbar-brand" href="/b">b</a>
		</span>
		<span class="nav-item">
			<a class="navbar-brand" href="/c">c</a>
		</span>
	</div>
</nav>
{{ end }}

我的假设是,因为在为匿名用户执行模板时没有传入admin.html模板,所以dashboard模板不会被解析。然而,我遇到了这个错误:

template: index.html:18:14: executing "index.html" at <{{template "dashboard"}}>: template "dashboard" not defined

我该如何修复这个问题,或者有没有更好的方法来实现这个功能?

英文:

I have a webpage with two views, one for the anonymous user and one for the admin user. I want to display a navbar only for the admin user. Everything else remains the same for both the user types.

This is what I've tried so far

main.go

package main
import (
&quot;log&quot;
&quot;net/http&quot;
&quot;text/template&quot;
&quot;github.com/julienschmidt/httprouter&quot;
)
func BasicAuth(h httprouter.Handle, requiredUser, requiredPassword string) httprouter.Handle {
return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
// Get the Basic Authentication credentials
user, password, hasAuth := r.BasicAuth()
if hasAuth &amp;&amp; user == requiredUser &amp;&amp; password == requiredPassword {
// Delegate request to the given handle
h(w, r, ps)
} else {
// Request Basic Authentication otherwise
w.Header().Set(&quot;WWW-Authenticate&quot;, &quot;Basic realm=Restricted&quot;)
http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
}
}
}
func Anonymous(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
t, err := template.ParseFiles(&quot;index.html&quot;)
if err != nil {
log.Fatalln(err)
}
err = t.Execute(w, map[string]string{&quot;Name&quot;: &quot;Anonymous&quot;})
if err != nil {
log.Fatalln(err)
}
}
func Admin(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
t, err := template.ParseFiles(&quot;index.html&quot;, &quot;admin.html&quot;)
if err != nil {
log.Fatalln(err)
}
err = t.Execute(w, map[string]string{&quot;Name&quot;: &quot;Admin&quot;})
if err != nil {
log.Fatalln(err)
}
}
func main() {
user := &quot;admin&quot;
pass := &quot;1234&quot;
router := httprouter.New()
router.GET(&quot;/&quot;, Anonymous)
router.GET(&quot;/admin/&quot;, BasicAuth(Admin, user, pass))
log.Fatal(http.ListenAndServe(&quot;:8080&quot;, router))
}

index.html

&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
&lt;head&gt;
&lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&gt;
&lt;title&gt;{{ .Name }}&lt;/title&gt;
&lt;link href=&quot;https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/css/bootstrap.min.css&quot; rel=&quot;stylesheet&quot;&gt;
&lt;script src=&quot;https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/js/bootstrap.bundle.min.js&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;https://code.jquery.com/jquery-3.6.4.min.js&quot;&gt;&lt;/script&gt;
&lt;script&gt;
function counter() {
document.getElementById(&quot;x&quot;).innerHTML = &quot;x: &quot; + document.querySelectorAll(&#39;.x&#39;).length;
document.getElementById(&quot;y&quot;).innerHTML = &quot;y: &quot; + document.querySelectorAll(&#39;.y&#39;).length;
document.getElementById(&quot;z&quot;).innerHTML = &quot;z: &quot; + document.querySelectorAll(&#39;.z&#39;).length;
}
&lt;/script&gt;
&lt;/head&gt;
&lt;body onload=&quot;counter()&quot;&gt;
{{ template &quot;dashboard&quot; }}
&lt;nav class=&quot;navbar fixed-bottom&quot;&gt;
&lt;div class=&quot;container-fluid nav-justified&quot;&gt;
&lt;span id=&quot;x&quot; class=&quot;navbar-brand nav-item&quot;&gt;&lt;/span&gt;
&lt;span id=&quot;y&quot; class=&quot;navbar-brand nav-item&quot;&gt;&lt;/span&gt;
&lt;span id=&quot;z&quot; class=&quot;navbar-brand nav-item&quot;&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;/nav&gt;
&lt;/body&gt;
&lt;/html&gt;

admin.html

{{ define &quot;dashboard&quot; }}
&lt;nav class=&quot;navbar&quot;&gt;
&lt;div class=&quot;container-fluid nav-justified&quot;&gt;
&lt;span class=&quot;nav-item&quot;&gt;
&lt;a class=&quot;navbar-brand&quot; href=&quot;/a&quot;&gt;a&lt;/a&gt;
&lt;/span&gt;
&lt;span class=&quot;nav-item&quot;&gt;
&lt;a class=&quot;navbar-brand&quot; href=&quot;/b&quot;&gt;b&lt;/a&gt;
&lt;/span&gt;
&lt;span class=&quot;nav-item&quot;&gt;
&lt;a class=&quot;navbar-brand&quot; href=&quot;/c&quot;&gt;c&lt;/a&gt;
&lt;/span&gt;
&lt;/div&gt;
&lt;/nav&gt;
{{ end }}

My assumption was that because I did not pass in the admin.html template while executing templates for the anonymous user, that the dashboard template would not be parsed. However, I run into this error:

template: index.html:18:14: executing &quot;index.html&quot; at &lt;{{template &quot;dashboard&quot;}}&gt;: template &quot;dashboard&quot; not defined

How do I fix this, or is there a better way to do this?

答案1

得分: 0

使用if语句在条件满足时有条件地渲染dashboard模板:

{{ if eq .Name "Admin" }} {{ template "dashboard" }} {{ end }}

而实践中的做法是只解析模板一次,而不是在每个请求上解析它:

package main

import (
	"log"
	"net/http"
	"sync"
	"text/template"

	"github.com/julienschmidt/httprouter"
)

func BasicAuth(h httprouter.Handle, requiredUser, requiredPassword string) httprouter.Handle {
	return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
		user, password, hasAuth := r.BasicAuth()

		if hasAuth && user == requiredUser && password == requiredPassword {
			h(w, r, ps)
		} else {
			w.Header().Set("WWW-Authenticate", "Basic realm=Restricted")
			http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
		}
	}
}

func Anonymous(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	err := tmpl.Execute(w, map[string]string{"Name": "Anonymous"})
	if err != nil {
		log.Fatalln(err)
	}
}

func Admin(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	err := tmpl.Execute(w, map[string]string{"Name": "Admin"})
	if err != nil {
		log.Fatalln(err)
	}
}

var (
	tmpl     *template.Template
	tmplOnce sync.Once
)

func main() {
	user := "admin"
	pass := "1234"

	tmplOnce.Do(func() {
		tmpl = template.Must(template.ParseFiles("index.html", "admin.html"))
	})

	router := httprouter.New()
	router.GET("/", Anonymous)
	router.GET("/admin/", BasicAuth(Admin, user, pass))

	log.Fatal(http.ListenAndServe(":8080", router))
}
英文:

Render the dashboard template conditionally with an if action:

{{ if eq .Name &quot;Admin&quot; }} {{ template &quot;dashboard&quot; }} {{ end }}

And the practice is to parse the template only once instead of parsing it on every request:

package main

import (
	&quot;log&quot;
	&quot;net/http&quot;
	&quot;sync&quot;
	&quot;text/template&quot;

	&quot;github.com/julienschmidt/httprouter&quot;
)

func BasicAuth(h httprouter.Handle, requiredUser, requiredPassword string) httprouter.Handle {
	return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
		user, password, hasAuth := r.BasicAuth()

		if hasAuth &amp;&amp; user == requiredUser &amp;&amp; password == requiredPassword {
			h(w, r, ps)
		} else {
			w.Header().Set(&quot;WWW-Authenticate&quot;, &quot;Basic realm=Restricted&quot;)
			http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
		}
	}
}

func Anonymous(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	err := tmpl.Execute(w, map[string]string{&quot;Name&quot;: &quot;Anonymous&quot;})
	if err != nil {
		log.Fatalln(err)
	}
}

func Admin(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	err := tmpl.Execute(w, map[string]string{&quot;Name&quot;: &quot;Admin&quot;})
	if err != nil {
		log.Fatalln(err)
	}
}

var (
	tmpl     *template.Template
	tmplOnce sync.Once
)

func main() {
	user := &quot;admin&quot;
	pass := &quot;1234&quot;

	tmplOnce.Do(func() {
		tmpl = template.Must(template.ParseFiles(&quot;index.html&quot;, &quot;admin.html&quot;))
	})

	router := httprouter.New()
	router.GET(&quot;/&quot;, Anonymous)
	router.GET(&quot;/admin/&quot;, BasicAuth(Admin, user, pass))

	log.Fatal(http.ListenAndServe(&quot;:8080&quot;, router))
}

huangapple
  • 本文由 发表于 2023年5月2日 18:47:27
  • 转载请务必保留本文链接:https://go.coder-hub.com/76154076.html
匿名

发表评论

匿名网友

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

确定