Golang reads html tags (<>) from JSON string data as &lt and &gt which causes rendering issues in the browser

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

Golang reads html tags (<>) from JSON string data as &lt and &gt which causes rendering issues in the browser

问题

我有一个基本的Web服务器,从一个JSON帖子数据库中呈现博客文章,其中主要段落是由JSON字符串数组构建的。我试图找到一种简单地编码换行或换行符的方法,并发现在这些值从JSON到GoLang再到我的HTML网页的编码方式上存在很多困难。当我尝试使用换行符对JSON进行编码时,我发现我必须使用\\n而不是\n来进行编码,以便它们实际上出现在我的页面上。然而,一个问题是它们只是作为文本而不是换行符显示出来。

然后,我尝试研究如何将连接的字符串数组中的\n部分替换为&lt;br&gt;标签,但是我无法找到任何在Go中实现此操作的方法,于是我尝试在JavaScript中实现。然而,即使我在HTML中延迟调用JavaScript,这也没有起作用。以下是我的JavaScript代码:

var title = window.document.getElementById("title");
var timestamp = window.document.getElementById("timestamp");
var sitemap = window.document.getElementById("sitemap");
var main = window.document.getElementById("main");
var contact_form = window.document.getElementById("contact-form");
var content_info = window.document.getElementById("content-info");

var str = main.innerHTML;

function replaceNewlines() {
    // Replace the \n with &lt;br&gt;
    str = str.replace(/(?:\r\n|\r|\n)/g, "&lt;br&gt;");

    // Update the value of paragraph
    main.innerHTML = str;
}

这是我的HTML代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Dynamic JSON Events</title>
    <link rel="stylesheet" href="/blogtemplate.css"></style>
</head>
<body>
    <section id="title">
        <h1 id="text-title">{{.Title}}</h1>
        <time id="timestamp">
		    {{.Timestamp}}
        </time>
    </section>
    <nav role="navigation" id="site-nav">
        <ul id="sitemap">
        </ul>
    </nav>
    <main role="main" id="main">
		{{.ParsedMain}}
    </main>
    <footer role="contentinfo" id="footer">
        <form id="contact-form" role="form">
        <address>
            Contact me by <a id="my-email" href="mailto:antonhibl11@gmail.com" class="my-email">e-mail</a>
        </address>
        </form>
    </footer>
<script defer src="/blogtemplate.js">
</script>
</body>
</html>

然后,我尝试在我的JSON数据中硬编码&lt;br&gt;标签,结果发现当它最终到达浏览器时,它们只是呈现为&lt和&gt。在不断引发问题的编码过程中,我对于如何在我的JSON字符串数据中轻松包含换行变得非常沮丧。我该如何在我想要的位置轻松地包含换行符?

这是我的Go脚本示例:

package main

import (
	"encoding/json"
	"html/template"
	"log"
	"net/http"
	"os"
	"regexp"
	"strings"
)

type BlogPost struct {
	Title      string   `json:"title"`
	Timestamp  string   `json:"timestamp"`
	Main       []string `json:"main"`
	ParsedMain string
}

// 当我尝试在下面实现它时,它似乎不起作用
var re = regexp.MustCompile(`\r\n|[\r\n\v\f\x{0085}\x{2028}\x{2029}]`)
func replaceRegexp(s string) string {
	return re.ReplaceAllString(s, "<br>\n")
}

var blogTemplate = template.Must(template.ParseFiles("./assets/docs/blogtemplate.html"))

func blogHandler(w http.ResponseWriter, r *http.Request) {
	blogstr := r.URL.Path[len("/blog/"):] + ".json"

	f, err := os.Open("db/" + blogstr)
	if err != nil {
		http.Error(w, err.Error(), http.StatusNotFound)
		return
	}
	defer f.Close()

	var post BlogPost
	if err := json.NewDecoder(f).Decode(&post); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	post.ParsedMain = strings.Join(post.Main, "")

    // post.ParsedMain = replaceRegexp(post.ParsedMain)

	if err := blogTemplate.Execute(w, post); err != nil {
		log.Println(err)
	}
}

func teapotHandler(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusTeapot)
	w.Write([]byte("<html><h1><a href='https://datatracker.ietf.org/doc/html/rfc2324/'>HTCPTP</h1><img src='https://external-content.duckduckgo.com/iu/?u=https%3A%2F%2Ftaooftea.com%2Fwp-content%2Fuploads%2F2015%2F12%2Fyixing-dark-brown-small.jpg&amp;f=1&amp;nofb=1' alt='Im a teapot'><html>"))
}

func faviconHandler(w http.ResponseWriter, r *http.Request) {
	http.ServeFile(w, r, "./assets/art/favicon.ico")
}

func main() {
	http.Handle("/", http.FileServer(http.Dir("/assets/docs")))
	http.HandleFunc("/blog/", blogHandler)
	http.HandleFunc("/favicon.ico", faviconHandler)
	http.HandleFunc("/teapot", teapotHandler)
	log.Fatal(http.ListenAndServe(":8080", nil))
}

这是我的JSON数据示例:

{
    "title" : "Finished My First Blog App",
    "timestamp": "Friday, March 18th, 11:39 AM",
    "main": [
        "It took me awhile to tidy everything up but I finally finished creating my first ",
        "blog app using Go along with JSON for my database. I plan on using this to document ",
        "my own thoughts and experiences as a programmer and cybersecurity researcher; things ",
        "like tutorials, thought-pieces, and journals on my own projects progress will be ",
        "posted here. I look forward to getting more used to writing and sharing my own story, ",
        "I think it will help me learn from doing and also hearing feedback from others.\\n\\n",
        "I utilized a handler function to dynamically read from my JSON database and template ",
        "data into my HTML template using the go html/template package as well as the encoding/json ",
        "to handling reading those objects. Next I had to make sure my CSS and JavaScript assets ",
        "would be served alongside this finished template in order for my styling to be output into ",
        "the browser. For this I used a FileServer function which allowed for me to serve linked ",
        "resources in my HTML boilerplate and have the server still locate blog resources dynamically. ",
        "Going forward I am looking to add better styling, more JavaScript elements to the page, and ",
        "more functionality to how my JSON data is encoded and parsed in order to create more complex ",
        "looking pages and blog posts."
    ]
}

我只是想找到一种在我的JSON字符串的长数组中轻松包含段落之间的空格的方法,但是我在Go中失败了,我的JavaScript似乎从来没有影响到我的网页(这不是我在这方面遇到的唯一问题,由于某种原因它似乎不想影响任何页面元素),而且我似乎无法直接在我的JSON中硬编码&lt;br&gt;标签,因为浏览器将其解释为&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;。我尝试过的任何方法都没有让我成功编码换行符。我该怎么办呢?

英文:

I have a basic web server that renders blog posts from a database of JSON posts wherein the main paragraphs are built from a JSON string array. I was trying to find a way to easily encode new lines or line breaks and found a lot of difficulty with how the encoding for these values changes from JSON to GoLang and finally to my HTML webpage. When I tried to encode my JSON with newlines I found I had to encode them using \\n rather than just \n in order for them to actually appear on my page. One problem however was they simply appeared as text and not line breaks.

I then tried to research ways to replace the \n portions of the joined string array into &lt;br&gt; tags, however I could not find any way to do this with go and moved to trying to do so in javascript. This did not work either despite me deferring the calling of my javascript in my link from my HTML. this is that javascript:

var title = window.document.getElementById(&quot;title&quot;);
var timestamp = window.document.getElementById(&quot;timestamp&quot;);
var sitemap = window.document.getElementById(&quot;sitemap&quot;);
var main = window.document.getElementById(&quot;main&quot;);
var contact_form = window.document.getElementById(&quot;contact-form&quot;);
var content_info = window.document.getElementById(&quot;content-info&quot;);
var str = main.innerHTML;
function replaceNewlines() {
// Replace the \n with &lt;br&gt;
str = str.replace(/(?:\r\n|\r|\n)/g, &quot;&lt;br&gt;&quot;);
// Update the value of paragraph
main.innerHTML = str;
}

Here is my HTML:

&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
&lt;head&gt;
&lt;meta charset=&quot;UTF-8&quot;&gt;
&lt;meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;IE=edge&quot;&gt;
&lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&gt;
&lt;title&gt;Dynamic JSON Events&lt;/title&gt;
&lt;link rel=&quot;stylesheet&quot; href=&quot;/blogtemplate.css&quot;&gt;&lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;section id=&quot;title&quot;&gt;
&lt;h1 id=&quot;text-title&quot;&gt;{{.Title}}&lt;/h1&gt;
&lt;time id=&quot;timestamp&quot;&gt;
{{.Timestamp}}
&lt;/time&gt;
&lt;/section&gt;
&lt;nav role=&quot;navigation&quot; id=&quot;site-nav&quot;&gt;
&lt;ul id=&quot;sitemap&quot;&gt;
&lt;/ul&gt;
&lt;/nav&gt;
&lt;main role=&quot;main&quot; id=&quot;main&quot;&gt;
{{.ParsedMain}}
&lt;/main&gt;
&lt;footer role=&quot;contentinfo&quot; id=&quot;footer&quot;&gt;
&lt;form id=&quot;contact-form&quot; role=&quot;form&quot;&gt;
&lt;address&gt;
Contact me by &lt;a id=&quot;my-email&quot; href=&quot;mailto:antonhibl11@gmail.com&quot; class=&quot;my-email&quot;&gt;e-mail&lt;/a&gt;
&lt;/address&gt;
&lt;/form&gt;
&lt;/footer&gt;
&lt;script defer src=&quot;/blogtemplate.js&quot;&gt;
&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;

I then finally turned to trying to hardcode &lt;br&gt; tags into my json data to discover that this simply renders as &lt and &gt when it finally reaches the browser. I am getting pretty frustrated with this process of encoding constantly causing me issues in creating newlines and line breaks. How can I easily include newlines where I want in my JSON string data?

Here is my Go script if it helps:

package main
import (
&quot;encoding/json&quot;
&quot;html/template&quot;
&quot;log&quot;
&quot;net/http&quot;
&quot;os&quot;
&quot;regexp&quot;
&quot;strings&quot;
)
type BlogPost struct {
Title      string   `json:&quot;title&quot;`
Timestamp  string   `json:&quot;timestamp&quot;`
Main       []string `json:&quot;main&quot;`
ParsedMain string
}
// this did not seem to work when I tried to implement it below
var re = regexp.MustCompile(`\r\n|[\r\n\v\f\x{0085}\x{2028}\x{2029}]`)
func replaceRegexp(s string) string {
return re.ReplaceAllString(s, &quot;&lt;br&gt;\n&quot;)
}
var blogTemplate = template.Must(template.ParseFiles(&quot;./assets/docs/blogtemplate.html&quot;))
func blogHandler(w http.ResponseWriter, r *http.Request) {
blogstr := r.URL.Path[len(&quot;/blog/&quot;):] + &quot;.json&quot;
f, err := os.Open(&quot;db/&quot; + blogstr)
if err != nil {
http.Error(w, err.Error(), http.StatusNotFound)
return
}
defer f.Close()
var post BlogPost
if err := json.NewDecoder(f).Decode(&amp;post); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
post.ParsedMain = strings.Join(post.Main, &quot;&quot;)
// post.ParsedMain = replaceRegexp(post.ParsedMain)
if err := blogTemplate.Execute(w, post); err != nil {
log.Println(err)
}
}
func teapotHandler(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusTeapot)
w.Write([]byte(&quot;&lt;html&gt;&lt;h1&gt;&lt;a href=&#39;https://datatracker.ietf.org/doc/html/rfc2324/&#39;&gt;HTCPTP&lt;/h1&gt;&lt;img src=&#39;https://external-content.duckduckgo.com/iu/?u=https%3A%2F%2Ftaooftea.com%2Fwp-content%2Fuploads%2F2015%2F12%2Fyixing-dark-brown-small.jpg&amp;f=1&amp;nofb=1&#39; alt=&#39;Im a teapot&#39;&gt;&lt;html&gt;&quot;))
}
func faviconHandler(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, &quot;./assets/art/favicon.ico&quot;)
}
func main() {
http.Handle(&quot;/&quot;, http.FileServer(http.Dir(&quot;/assets/docs&quot;)))
http.HandleFunc(&quot;/blog/&quot;, blogHandler)
http.HandleFunc(&quot;/favicon.ico&quot;, faviconHandler)
http.HandleFunc(&quot;/teapot&quot;, teapotHandler)
log.Fatal(http.ListenAndServe(&quot;:8080&quot;, nil))
}

Here is an example of my JSON data:

{
&quot;title&quot; : &quot;Finished My First Blog App&quot;,
&quot;timestamp&quot;: &quot;Friday, March 18th, 11:39 AM&quot;,
&quot;main&quot;: [
&quot;It took me awhile to tidy everything up but I finally finished creating my first &quot;,
&quot;blog app using Go along with JSON for my database. I plan on using this to document &quot;,
&quot;my own thoughts and experiences as a programmer and cybersecurity researcher; things &quot;,
&quot;like tutorials, thought-pieces, and journals on my own projects progress will be &quot;,
&quot;posted here. I look forward to getting more used to writing and sharing my own story, &quot;,
&quot;I think it will help me learn from doing and also hearing feedback from others.\\n\\n&quot;,
&quot;I utilized a handler function to dynamically read from my JSON database and template &quot;,
&quot;data into my HTML template using the go html/template package as well as the encoding/json &quot;,
&quot;to handling reading those objects. Next I had to make sure my CSS and JavaScript assets &quot;,
&quot;would be served alongside this finished template in order for my styling to be output into &quot;,
&quot;the browser. For this I used a FileServer function which allowed for me to serve linked &quot;,
&quot;resources in my HTML boilerplate and have the server still locate blog resources dynamically. &quot;,
&quot;Going forward I am looking to add better styling, more JavaScript elements to the page, and &quot;,
&quot;more functionality to how my JSON data is encoded and parsed in order to create more complex &quot;,
&quot;looking pages and blog posts.&quot;
]
}

I am just trying to find a way to easily include spaces between paragraphs in the long array of strings in my JSON however I have failed in Go, my JS doesn't ever seem to affect my webpage(this is not the only problem I have had with this, it does not seem to want to affect any page elements for some reason), and I cannot seem to hardcode &lt;br&gt; tags directly into my JSON as the browser interprets those as &amp;lt;br&amp;gt;&amp;lt;br&amp;gt;. Nothing I have tried has actually let me encode linebreaks, What can I do here?

答案1

得分: 2

你可以尝试在模板中循环遍历数组,并为数组的每个元素生成一个 <p> 标签。这样就不需要在 Go 中编辑主数组。

模板:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Dynamic JSON Events</title>
    <link rel="stylesheet" href="/blogtemplate.css"></style>
</head>
<body>
    <section id="title">
        <h1 id="text-title">{{.Title}}</h1>
        <time id="timestamp">
            {{.Timestamp}}
        </time>
    </section>
    <nav role="navigation" id="site-nav">
        <ul id="sitemap">
        </ul>
    </nav>
    <main role="main" id="main">
        {{range $element := .Main}} <p>{{$element}}</p> {{end}}
    </main>
    <footer role="contentinfo" id="footer">
        <form id="contact-form" role="form">
        <address>
            Contact me by <a id="my-email" href="mailto:antonhibl11@gmail.com" class="my-email">e-mail</a>
        </address>
        </form>
    </footer>
<script defer src="/blogtemplate.js">
</script>
</body>
</html>
英文:

You could try to loop over your array inside the template and generate a p tag for every element of the array. This way there is no need to edit your main array in go.

Template:

&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
&lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot;&gt;
    &lt;meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;IE=edge&quot;&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&gt;
    &lt;title&gt;Dynamic JSON Events&lt;/title&gt;
    &lt;link rel=&quot;stylesheet&quot; href=&quot;/blogtemplate.css&quot;&gt;&lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;section id=&quot;title&quot;&gt;
        &lt;h1 id=&quot;text-title&quot;&gt;{{.Title}}&lt;/h1&gt;
        &lt;time id=&quot;timestamp&quot;&gt;
            {{.Timestamp}}
        &lt;/time&gt;
    &lt;/section&gt;
    &lt;nav role=&quot;navigation&quot; id=&quot;site-nav&quot;&gt;
        &lt;ul id=&quot;sitemap&quot;&gt;
        &lt;/ul&gt;
    &lt;/nav&gt;
    &lt;main role=&quot;main&quot; id=&quot;main&quot;&gt;
        {{range $element := .Main}} &lt;p&gt;{{$element}}&lt;/p&gt; {{end}}
    &lt;/main&gt;
    &lt;footer role=&quot;contentinfo&quot; id=&quot;footer&quot;&gt;
        &lt;form id=&quot;contact-form&quot; role=&quot;form&quot;&gt;
        &lt;address&gt;
            Contact me by &lt;a id=&quot;my-email&quot; href=&quot;mailto:antonhibl11@gmail.com&quot; class=&quot;my-email&quot;&gt;e-mail&lt;/a&gt;
        &lt;/address&gt;
        &lt;/form&gt;
    &lt;/footer&gt;
&lt;script defer src=&quot;/blogtemplate.js&quot;&gt;
&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;

答案2

得分: 1

如果您希望JSON文档包含HTML内容,请按照以下步骤进行操作:

  1. 将ParsedMain更改为类型html.HTML

     type BlogPost struct {
    ...
    ParsedMain html.HTML
    }
    
  2. 在分配字段时将其转换为该类型:

     post.ParsedMain = html.HTML(strings.Join(post.Main, "")).
    
  3. 在文档中将``\n替换为<br>`。

如果不受信任的用户可以输入JSON文档数据,则应用程序应该根据允许列表对HTML标签和属性进行过滤。这可以防止攻击者通过脚本注入发起攻击。

如果您希望在JSON文档中将换行符转换为HTML中的换行符,请按照以下步骤进行操作:

  1. 将文档中的换行符更改为包含换行符的形式:\\n -> \n

  2. 在服务器端或客户端上,将换行符替换为HTML换行符。为了防止脚本注入攻击,在插入&lt;br&gt;之前,请对HTML进行转义。以下是在服务器端执行此操作的方法:

     type BlogPost struct {
    ...
    ParsedMain html.HTML
    }
    escapedAndJoined := html.Escaper(post.Main...)
    post.ParsedMain = html.HTML(strings.ReplaceAll(escapedAndJoined, "\n", "&lt;br&gt;")).
    

您可能希望使用&lt;p&gt;而不是&lt;br&gt;

英文:

If you want the JSON document to contain HTML, then do the following:

  1. Change ParsedMain to type html.HTML:

     type BlogPost struct {
    ...
    ParsedMain html.HTML
    }
    
  2. Convert to that type when assigning the field:

     post.ParsedMain = html.HTML(strings.Join(post.Main, &quot;&quot;)).
    
  3. Replace ``\nwith<br>` in the document.

If untrusted users can enter the JSON document data, then the application should filter the HTML tags and attributes against an allow list. This prevents an attacker mounting an attack through script injection.

If you want translate newlines in the JSON document to line breaks in HTML, then do the following:

  1. Change the document to include newlines: \\n -> \n.

  2. On the server or the client, replace the newlines with an HTML line break. To prevent script injection attacks, escape HTML before inserting the &lt;br&gt;. Here's how to do it on the server:

     type BlogPost struct {
    ...
    ParsedMain html.HTML
    }
    escapedAndJoined := html.Escaper(post.Main...)
    post.ParsedMain = html.HTML(strings.ReplaceAll(escapedAndJoined, &quot;\n&quot;, &quot;&lt;br&gt;&quot;))).
    

You may want to use &lt;p&gt; instead of &lt;br&gt;.

huangapple
  • 本文由 发表于 2022年3月19日 13:38:31
  • 转载请务必保留本文链接:https://go.coder-hub.com/71535674.html
匿名

发表评论

匿名网友

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

确定