Подтвердить что ты не робот

Перейти template.ExecuteTemplate включает html

Я следовал этому руководству: http://golang.org/doc/articles/wiki/final.go и немного изменил его для моих потребностей/желаний. Проблема в том, что я хочу поддерживать HTML в шаблонах. Я понимаю, что это риск для безопасности, но это не проблема на данный момент.

Результат рендеринга страницы:

<h1>this<strong>is</strong>a test</h1>

Позвольте мне немного пояснить код:

type Page struct {
    Title string
    Body  []byte
}

Данные, которые я хотел бы иметь HTML, хранятся в Page.Body. Это тип []byte, который означает, что я не могу (или могу?) Запустить html/template.HTML(Page.Body), поскольку эта функция ожидает строку.

У меня есть это, которое предварительно отображает шаблоны:

var (
    templates = template.Must(template.ParseFiles("tmpl/edit.html", "tmpl/view.html"))
)

И фактическое ExecuteTemplate выглядит так:

err := templates.ExecuteTemplate(w, tmpl+".html", p)

Где w w http.ResponseWriter, tmpl tmpl string, а p - p *Page

Наконец, мой 'view.html' (шаблон) выглядит следующим образом:

<h1>{{.Title}}</h1>
<p>[<a href="/edit/{{.Title}}">edit</a>]</p>
<div>{{printf "%s" .Body}}</div>

Что я пробовал:

  • {{printf "%s" .Body | html}} ничего не делает
  • Я включил github.com/russross/blackfriday (процессор Markdown) и запустил p.Body = blackfriday.MarkdownCommon(p.Body), который корректно преобразует Markdown в HTML, но HTML все равно выводится как объекты.
  • EDIT: Я попытался выполнить следующий бит кода (я не знаю, почему формат испорчен), и он все равно выводит то же самое.

    var s template.HTML s = template.HTML(p.Body) p.Body = []byte(s)

Любые рекомендации приветствуются. Если я запутаюсь, спросите меня, и я могу изменить свой вопрос.

4b9b3361

Ответ 1

Преобразуйте []byte или string, чтобы напечатать template.HTML (зарегистрированный здесь)

p.Body = template.HTML(s) // where s is a string or []byte

Затем в вашем шаблоне просто:

{{.Body}}

Он будет напечатан без экранирования.

ИЗМЕНИТЬ

Чтобы иметь возможность включать HTML в тело страницы, вам нужно изменить объявление типа Page:

type Page struct {
    Title string
    Body  template.HTML
}

затем назначьте его.

Ответ 2

Взгляните на template.HTML. Его можно использовать для инкапсуляции известного безопасного фрагмента HTML (например, выход из Markdown). Пакет "html/template" не сможет избежать этого типа.

type Page struct {
    Title string
    Body template.HTML
}

page := &Page{
    Title: "Example",
    Body:  template.HTML(blackfriday.MarkdownCommon([]byte("foo bar")),
}

Обычно я пишу свой собственный метод func Markdown(text string) html.Template, который вызывает blackfriday с соответствующей конфигурацией и делает некоторые преобразования типов. Другой альтернативой может быть также регистрация функции "html" в парсере шаблонов, которая позволяет выводить любое значение без какого-либо выхода, делая что-то вроде {{html .MySafeStr}}. Код может выглядеть так:

var tmpl = template.Must(template.New("").Funcs(template.FuncMap{
    "html": func(value interface{}) template.HTML {
        return template.HTML(fmt.Sprint(value))
    },
}).ParseFiles("file1.html", "file2.html"))

Ответ 3

Я создал пользовательскую функцию для шаблона следующим образом:

func noescape(str string) template.HTML {
    return template.HTML(str)
}

var fn = template.FuncMap{
    "noescape": noescape,
}

Затем на вашем шаблоне:

{{ noescape $x.Body }}

Ответ 4

Я использую Beego и React.js и часами пытаюсь запустить парсер JSX. Оказывается, html/template выделяет комментарии, особенно блок js doc/** @jsx React.DOM */.

Обходите его, создавая специальный метод для ввода комментария как JS и вызова его из шаблона.

// Create a method in your controller (I'm using Beego)
func jsxdoc()(out template.JS) {
    return template.JS(`/** @jsx React.DOM */`)
}

// Add method to your function map available to views
beego.AddFuncMap("jsxdoc", jsxdoc)

// In template
<script type="text/jsx">
    {{ jsxdoc }}
    var CommentBox = React.createClass({
      render: function() {
        return (
          <div class="commentBox">
            Hello, world! I am a CommentBox.
          </div>
        );
      }
    });
    React.renderComponent(
      <CommentBox />,
      document.getElementById('content')
    );
</script>

Ответ 5

Вот подход, который не требует каких-либо изменений в ваших существующих структурах и очень минимальное добавление к вашим шаблонам:

Измените эти строки:

var (
    templates = template.Must(template.ParseFiles("tmpl/edit.html", "tmpl/view.html"))
)

к этому (включите funcmap с функцией, которая выведет неэкранированный HTML):

var templates = template.Must(template.New("main").Funcs(template.FuncMap{
    "safeHTML": func(b []byte) template.HTML {
        return template.HTML(b)
    },
}).ParseFiles("tmpl/edit.html", "tmpl/view.html"))

А потом просто измените свой HTML-код шаблона следующим образом:

<div>{{printf "%s" .Body}}</div>

к этому (используйте свою новую функцию):

<div>{{ .Body | safeHTML }}</div>

Намного проще!

Ответ 6

Для уточнения и более простого способа передачи HTML в шаблон см.

https://groups.google.com/forum/#!topic/golang-nuts/8L4eDkr5Q84

Просто создайте свою строку HTML через go и передайте ее в свой шаблон, например:

Sout := ""
.
.

    Sout += fmt.Sprintf(`<tr><td>%s<td align=center>%.2f<td>%s<td>%s<td>%s<td>%s<td align=center>%d<td align=center>%d
                    <td align=center>%d`, AccountID, amount, remissiondetails, created, begins, ends,
                    freePDFs, freeinformants, freeSDQs)

.
.
    render(w, "templates/Waivers.html", map[string]interface{}{ "Body":template.HTML(Sout), })

Ответ 7

Почему бы не преобразовать []byte в строку? Вы можете сделать это следующим образом:

str := string(page.Body)