在Go模板中请求上下文。

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

Request context in a Go template

问题

我想在Go的HTML模板中编写这样一个条件片段:

{{if isUserAdmin}}
   <a href="/admin/nuke">前往大红色核按钮</a>
{{end}}

然而,直接这样做是不可能的,因为模板不知道触发其执行的请求,所以无法确定用户是否是管理员。

有没有一种常规的方法来实现这个?

提前指出:

  • 我不想为这个特定的数据使用管道(参见关于此的其他问题)。
  • 我承认只有处理程序/控制器应该处理逻辑,视图只应进行渲染。但条件{{if isUserAdmin}}本身并不是逻辑,它是一个必要的结构,用于利用控制器已经计算出的布尔值。
  • Funcs方法可能有所帮助,但目前还不够简洁,不能轻松定义特定的isUserAdmin()方法。
英文:

I would like to write such a conditional fragment in a Go HTML template :

  {{if isUserAdmin}}
     &lt;a href&quot;/admin/nuke&quot;&gt;Go to the big red nuclear button&lt;/a&gt;
  {{end}}

However, this is not directly possible because the template is not aware of the request that triggered its execution, so it cannot determine if the user is admin or not.

Is there some normal way to achieve this ?

In advance I point out that :

  • I do not want to use Pipelines for this specific data (see other question about this)
  • I acknowledge that only the handlers/controllers should deal with logic, and views should only do the rendering. But the condition {{if isUserAdmin}} is not logic itself, it's a necessary construct to leverage a boolean value already calculated by the controller.
  • The Funcs method can help, but is currently not lean enough for easily defining specific method isUserAdmin()

答案1

得分: 4

我同意Darshan Computing的观点,我认为从请求中传递信息的正确方式是通过管道。您可以将数据分为要呈现的数据和上下文,例如,通过在模板数据结构中嵌入它们,以清楚地区分两者:

type TemplateData struct {
    *Content
    *Context
}

例如,这样可以得到这个。然后,根据共享和查询特定的内容,您可以重复使用一些上下文/内容信息。

英文:

I would agree with Darshan Computing, I think the proper way of passing information from the request would be in the pipeline. You can have your data being split between the data you want to render and the context, e.g. by having your template data structure embed them both if you want to clearly separate the two:

type TemplateData struct {
    *Content
    *Context
}

Which gives this for example. You can then reuse some of your context/content information depending on what is shared and what is query specific.

答案2

得分: 3

这是一个使用Funcs来覆盖"isAdmin"工作解决方案尝试(Playground链接),在模板编译之后但在每次执行之前(感谢Valentin CLEMENT在其他问题中的帮助)。

但是它有几个缺点:

  • 在模板编译之前声明一个空的虚拟的"isAdmin"函数看起来很奇怪。

  • (使用Funcs多次很麻烦,因为我不能只覆盖一个单独的方法,我必须提供一个完整的FuncMap,包含所有的函数)编辑:实际上之前的funcs并没有丢失,我对此有误解。

  • 它本质上不是线程安全的,在多个goroutine修改和执行相同的模板时会失败。

英文:

Here is a working solution attempt (link to Playground) using Funcs to overwrite &quot;isAdmin&quot;, after template compilation but before each execution (thanks to Valentin CLEMENT in other question).

But it has several flaws :

  • It is weird to declare a dummy empty &quot;isAdmin&quot; function before template compilation.
  • (Using Funcs several times is painful because I cannot just overwrite a single method, I have to provide a complete FuncMap with all the functions) edit : in fact previous funcs are not lost, i was wrong about that.
  • It is inherently not thread-safe and will fail when several goroutines alter and execute the same template

答案3

得分: 3

正常的做法是简单地将模板传递给一个包含任何静态数据的结构体。除非我对你的尝试有误解,否则在这里似乎没有必要使用Funcs。简化你的示例代码如下:

package main

import (
    "html/template"
    "os"
)

const hometmpl = `
{{if .IsAdmin}}
  <a href="/admin/nuke">Go to the big red nuclear button</a>
{{end}}
`

var t = template.Must(template.New("home").Parse(hometmpl))

func isAdmin(token string) bool {
    const adminToken = "0xCAFEBABE"
    return token == adminToken
}

func main() {
    token := "0xCAFEBABE" // 或者从http.Request中提取
    t.ExecuteTemplate(os.Stdout, "home", struct{IsAdmin bool}{isAdmin(token)})
}

希望对你有所帮助!

英文:

The normal thing to do is to simply pass your template a struct with whatever static data you like. Unless I've misunderstood what you're trying to do, there doesn't seem to be any need for Funcs here. Simplifying your example:

package main

import (
    &quot;html/template&quot;
    &quot;os&quot;
)

const hometmpl = `
{{if .IsAdmin}}
  &lt;a href=&quot;/admin/nuke&quot;&gt;Go to the big red nuclear button&lt;/a&gt;
{{end}}
`

var t = template.Must(template.New(&quot;home&quot;).Parse(hometmpl))

func isAdmin(token string) bool {
    const adminToken = &quot;0xCAFEBABE&quot;
    return token == adminToken
}

func main() {
    token := &quot;0xCAFEBABE&quot; // Or extracted from the http.Request
    t.ExecuteTemplate(os.Stdout, &quot;home&quot;, struct{IsAdmin bool}{isAdmin(token)})
}

huangapple
  • 本文由 发表于 2013年8月19日 03:24:09
  • 转载请务必保留本文链接:https://go.coder-hub.com/18302853.html
匿名

发表评论

匿名网友

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

确定