为什么和什么时候ResponseWriter会生成原始html? [英] Why and when would a ResponseWriter generate raw html?

查看:71
本文介绍了为什么和什么时候ResponseWriter会生成原始html?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我不明白为什么代码会正确生成view.html和post.html数据,但将其全部显示为原始文本。我一直在遵循 https://golang.org/doc/articles/\" rel=\"nofollow\">这里的指导,并且在我构建它时,我认为生成的html从执行功能将被发送到ResponserWriter将处理显示它,但我得到的错误似乎表明我对Execute或ResponseWriter的理解是错误的。



<$ (
os
fmt
time
bufio
net / http
html / template


类型UserPost结构{
名称字符串
关于字符串
PostTime字符串
}

func check(e error){
if e!= nil {
fmt.Println(Error Recieved ...)
panic(e)
}
}


func lineCounter(workingFile * os.File)int {
fileScanner:= bufio.NewScanner (workingFile)
lineCount:= 0
for fileScanner.Scan(){
lineCount ++
}
return lineCount

$ b $ func loadPage(i int)(* UserPost,error){
Posts,err:= os.Open(dataf.txt )
check(err)
var PostArray [512] UserPost = parsePosts(Posts,i)
Name:= PostArray [i] .Name
关于:= PostArray [i] .About
PostTime:= PostArray [i] .PostTime
Posts.Close()
return& UserPost {Name:Name [:len(Name)-1],About: :len(About)-1],PostTime:PostTime [:len(PostTime)-1]},nil
}

func viewHandler(w http.ResponseWriter,r * http.Request ){
tmp,err:= os.Open(dataf.txt)
check(err)
num:=(lineCounter(tmp)/ 3)
tmp。关闭()
for i:= 0;我< NUM; i ++ {
p,_:= loadPage(i)
t,_:= template.ParseFiles(view.html)
t.Execute(w,p)
}
p:= UserPost {名称:,关于:,PostTime:}
t,_:= template.ParseFiles(post.html)
t.Execute(w, p)
}

func inputHandler(w http.ResponseWriter,r * http.Request){
名称:= r.FormValue(person)
关于:= r.FormValue(body)
PostTime:= time.Now()。String()

filePaste,err:= os.OpenFile(dataf.txt,os .O_RDWR | os.O_CREATE | os.O_APPEND | os.SEEK_END,0666)
check(err)
filePaste.WriteString(Name +〜\\\

filePaste.WriteString(About + 〜\\\

filePaste.WriteString(PostTime +〜\\\

filePaste.Close()
fmt.Println(Data received:,Name,About, PostTime)
http.Redirect(w,r,/#bottom,http.StatusFound)//使用/#bottom进入html页面的底部。
}

//os.File是文件类型。
func parsePosts(fileToParse * os.File,num int)[512] UserPost {
var buffer [512] UserPost
reader:= bufio.NewReader(fileToParse)

//这个For循环读取每个论坛帖子,然后将其保存到缓冲区,然后迭代到下一个。
for i:= 0; i <= num; i ++ {
currentPost:= new(UserPost)
str,err:= reader.ReadString('〜')
check(err)
currentPost.Name = str

//我搜索'〜'是因为我的文件保存了读取行的末尾,所以我可以保存格式(\ n位置)。
str2,err2:= reader.ReadString('〜')
check(err2)
currentPost.About = str2

str3,err3:= reader.ReadString ('〜')
check(err3)
currentPost.PostTime = str3

buffer [i] = * currentPost
}
返回缓冲区


func main(){
fmt.Println(Listening ...)
http.HandleFunc(/,viewHandler)
http .HandleFunc(/ post /,inputHandler)
http.ListenAndServe(:8080,nil)
}

view.html

 < h4> {{。Name}}  H4> 

< font size =3>
< div> {{printf%s.About}}< / div>
< / font>
< br>
< font size =2align =right>
< div align =right> {{。PostTime}}< / div>
< / font>

post.html

 < form action =/ post /method =POST> 

< div>< textarea name =personrows =1cols =30> {{printf%s.Name}}< / textarea>< / DIV>

< div>< textarea name =bodyrows =5cols =100> {{printf%s.About}}< / textarea>< / DIV>

< div>< input type =submitvalue =Submit>< / div>

< a name =bottom>< / a>
< / form>

我目前正在读取一个空的dataf.txt文件。

解决方案

据暗示,这是因为你没有设置内容类型。从 http.ResponseWriter 引用:

  // Write将数据作为HTTP回复的一部分写入连接。 
//如果WriteHeader尚未被调用,Write在写入数据之前调用WriteHeader(http.StatusOK)
// //。如果标题不包含
// Content-Type行,则Write将Content-Type集添加到传递
//将写入数据的最初512字节传递给DetectContentType的结果中。
Write([] byte)(int,error)

如果您没有设置你自己的内容类型,首先调用 ResponseWriter.Write()将调用 http.DetectContentType() 来猜测要设置的内容。如果您发送的内容以< form>开头,它将不会被检测为HTML,而是text / plain; charset = utf-8将会被设置(它指示浏览器将内容显示为文本,而不是将其解释为HTML)。



<例如,如果内容以< html>开头,则内容类型text / html; charset = utf-8会被自动设置,并且不会采取进一步的行动。



但是如果你知道你要发送什么,不要依靠自动检测,也可以自己设置,而不是在其上运行检测算法,因此只需在写入/发送任何数据之前添加此行即可:

  w.Header()。Set(Content-Type,text / html; charset = utf-8)

还可以使 post.html 模板成为一个完整的,有效的HTML文档。

另一个建议:在你的代码中,你虔诚地忽略检查ret呃错误。不要这样做。你至少可以做的是在控制台上打印它们。如果您不遗漏错误,您将节省大量时间。


I don't understand why the code is generating the view.html and post.html data correctly but displaying it all as raw text. I had been following the guide here and as I was building it, I thought that the generated html from the Execute function would be sent to the ResponserWriter which would handle displaying it, but the error I'm getting seems to indicate my understanding of Execute or the ResponseWriter is wrong.

package main

import (
    "os"
    "fmt"
    "time"
    "bufio"
    "net/http"
    "html/template"
)

type UserPost struct {
    Name string
    About string
    PostTime string
}

func check(e error) {
    if e != nil {
        fmt.Println("Error Recieved...")
        panic(e)
    }
}


func lineCounter(workingFile *os.File) int {
    fileScanner := bufio.NewScanner(workingFile)
    lineCount := 0
    for fileScanner.Scan() {
        lineCount++
    }
    return lineCount
}

func loadPage(i int) (*UserPost, error) {
    Posts,err := os.Open("dataf.txt")
    check(err)
    var PostArray [512]UserPost = parsePosts(Posts,i)
    Name := PostArray[i].Name 
    About := PostArray[i].About
    PostTime := PostArray[i].PostTime
    Posts.Close()
    return &UserPost{Name: Name[:len(Name)-1], About: About[:len(About)-1], PostTime: PostTime[:len(PostTime)-1]}, nil
}

func viewHandler(w http.ResponseWriter, r *http.Request) {
    tmp,err := os.Open("dataf.txt")
    check(err)
    num := (lineCounter(tmp)/3)
    tmp.Close()
    for i := 0; i < num; i++ {
        p, _ := loadPage(i)
        t, _ := template.ParseFiles("view.html")
        t.Execute(w, p)
    }
    p := UserPost{Name: "", About: "", PostTime: ""}
    t, _ := template.ParseFiles("post.html")
    t.Execute(w, p)
}

func inputHandler(w http.ResponseWriter, r *http.Request) {
    Name := r.FormValue("person")
    About := r.FormValue("body")
    PostTime := time.Now().String()

    filePaste,err := os.OpenFile("dataf.txt", os.O_RDWR | os.O_CREATE | os.O_APPEND | os.SEEK_END, 0666)
    check(err)
    filePaste.WriteString(Name+"~\n")
    filePaste.WriteString(About+"~\n")
    filePaste.WriteString(PostTime+"~\n")
    filePaste.Close()
    fmt.Println("Data recieved: ", Name,About,PostTime)
    http.Redirect(w, r, "/#bottom", http.StatusFound) //Use "/#bottom" to go to bottom of html page.
}

//os.File is the file type.
func parsePosts(fileToParse *os.File,num int) [512]UserPost {
    var buffer [512]UserPost
    reader := bufio.NewReader(fileToParse)  

    //This For loop reads each "forum post" then saves it to the buffer, then iterates to the next.
    for i := 0;i <= num; i++ {
        currentPost := new(UserPost)
        str, err := reader.ReadString('~')
        check(err)
        currentPost.Name = str

        //I search for '~' because my files save the end of reading line with that, so i can keep formatting saved (\n placement).
        str2, err2 := reader.ReadString('~')
        check(err2)
        currentPost.About = str2

        str3, err3 := reader.ReadString('~')
        check(err3)
        currentPost.PostTime = str3

        buffer[i] = *currentPost
        }   
    return buffer
}

func main() {
    fmt.Println("Listening...")
    http.HandleFunc("/", viewHandler)
    http.HandleFunc("/post/", inputHandler)
    http.ListenAndServe(":8080", nil)
}   

view.html

<h4>{{.Name}}</h4>

<font size="3">
    <div>{{printf "%s" .About}}</div>
</font>
<br>
<font size="2" align="right">
    <div align="right">{{.PostTime}}</div>
</font>

post.html

<form action="/post/" method="POST">

<div><textarea name="person" rows="1" cols="30">{{printf "%s" .Name}}</textarea></div>

<div><textarea name="body" rows="5" cols="100">{{printf "%s" .About}}</textarea></div>

<div><input type="submit" value="Submit"></div>

<a name="bottom"></a>
</form>

I've currently been reading from an empty dataf.txt file.

解决方案

As hinted, it's because you haven't set the content type. Quoting from http.ResponseWriter:

// Write writes the data to the connection as part of an HTTP reply.
// If WriteHeader has not yet been called, Write calls WriteHeader(http.StatusOK)
// before writing the data.  If the Header does not contain a
// Content-Type line, Write adds a Content-Type set to the result of passing
// the initial 512 bytes of written data to DetectContentType.
Write([]byte) (int, error)

If you don't set the content type yourself, first call to ResponseWriter.Write() will call http.DetectContentType() to guess what to set. If the content you send starts with "<form>", it won't be detected as HTML, but "text/plain; charset=utf-8" will be set (which "instructs" the browser to display the content as text and not try to interpret it as HTML).

If the content would start with "<html>" for example, content type "text/html; charset=utf-8" would be set automatically and it would work without further actions.

But don't rely on automatic detection if you know what you're sending, also it's much faster to set it yourself than to run a detection algorithm on it, so simply add this line before writing/sending any data:

w.Header().Set("Content-Type", "text/html; charset=utf-8")

And also make your post.html template a complete, valid HTML document.

Also another piece of advice: in your code you religiously omit checking returned errors. Don't do that. The least you could do is print them on the console. You will save a lot of time for yourself if you don't omit errors.

这篇关于为什么和什么时候ResponseWriter会生成原始html?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆