// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build ignore
packagemainimport("fmt""os")typePagestruct{TitlestringBody[]byte}func(p*Page)save()error{filename:=p.Title+".txt"returnos.WriteFile(filename,p.Body,0600)}funcloadPage(titlestring)(*Page,error){filename:=title+".txt"body,err:=os.ReadFile(filename)iferr!=nil{returnnil,err}return&Page{Title:title,Body:body},nil}funcmain(){p1:=&Page{Title:"TestPage",Body:[]byte("This is a sample Page.")}p1.save()p2,_:=loadPage("TestPage")fmt.Println(string(p2.Body))}
介绍net/http包(一个中间件)
下面是一个简单的Web服务器的完整工作实例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//go:build ignore
packagemainimport("fmt""log""net/http")funchandler(whttp.ResponseWriter,r*http.Request){fmt.Fprintf(w,"Hi there, I love %s!",r.URL.Path[1:])}funcmain(){http.HandleFunc("/",handler)log.Fatal(http.ListenAndServe(":8080",nil))}
// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build ignore
packagemainimport("fmt""log""net/http""os")typePagestruct{TitlestringBody[]byte}func(p*Page)save()error{filename:=p.Title+".txt"returnos.WriteFile(filename,p.Body,0600)}funcloadPage(titlestring)(*Page,error){filename:=title+".txt"body,err:=os.ReadFile(filename)iferr!=nil{returnnil,err}return&Page{Title:title,Body:body},nil}funcviewHandler(whttp.ResponseWriter,r*http.Request){title:=r.URL.Path[len("/view/"):]p,_:=loadPage(title)fmt.Fprintf(w,"<h1>%s</h1><div>%s</div>",p.Title,p.Body)}funcmain(){http.HandleFunc("/view/",viewHandler)log.Fatal(http.ListenAndServe(":8080",nil))}
// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build ignore
packagemainimport("html/template""log""net/http""os")typePagestruct{TitlestringBody[]byte}func(p*Page)save()error{filename:=p.Title+".txt"returnos.WriteFile(filename,p.Body,0600)}funcloadPage(titlestring)(*Page,error){filename:=title+".txt"body,err:=os.ReadFile(filename)iferr!=nil{returnnil,err}return&Page{Title:title,Body:body},nil}funcrenderTemplate(whttp.ResponseWriter,tmplstring,p*Page){t,_:=template.ParseFiles(tmpl+".html")t.Execute(w,p)}funcviewHandler(whttp.ResponseWriter,r*http.Request){title:=r.URL.Path[len("/view/"):]p,_:=loadPage(title)renderTemplate(w,"view",p)}funceditHandler(whttp.ResponseWriter,r*http.Request){title:=r.URL.Path[len("/edit/"):]p,err:=loadPage(title)iferr!=nil{p=&Page{Title:title}}renderTemplate(w,"edit",p)}funcmain(){http.HandleFunc("/view/",viewHandler)http.HandleFunc("/edit/",editHandler)//http.HandleFunc("/save/", saveHandler)
log.Fatal(http.ListenAndServe(":8080",nil))}
What if you visit /view/APageThatDoesntExist? You’ll see a page containing HTML. This is because it ignores the error return value from loadPage and continues to try and fill out the template with no data. Instead, if the requested Page doesn’t exist, it should redirect the client to the edit Page so the content may be created:
funcgetTitle(whttp.ResponseWriter,r*http.Request)(string,error){m:=validPath.FindStringSubmatch(r.URL.Path)ifm==nil{http.NotFound(w,r)return"",errors.New("invalid Page Title")}returnm[2],nil// The title is the second subexpression.
}
如果标题是有效的,它将和一个nil错误值一起被返回。如果标题无效,该函数将向HTTP连接写一个 “404 Not Found “错误,并向处理程序返回一个错误。要创建一个新的错误,我们必须导入errors包。
funcmakeHandler(fnfunc(http.ResponseWriter,*http.Request,string))http.HandlerFunc{returnfunc(whttp.ResponseWriter,r*http.Request){// Here we will extract the page title from the Request,
// and call the provided handler 'fn'
}}
// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build ignore
packagemainimport("html/template""log""net/http""os""regexp")typePagestruct{TitlestringBody[]byte}func(p*Page)save()error{filename:=p.Title+".txt"returnos.WriteFile(filename,p.Body,0600)}funcloadPage(titlestring)(*Page,error){filename:=title+".txt"body,err:=os.ReadFile(filename)iferr!=nil{returnnil,err}return&Page{Title:title,Body:body},nil}funcviewHandler(whttp.ResponseWriter,r*http.Request,titlestring){p,err:=loadPage(title)iferr!=nil{http.Redirect(w,r,"/edit/"+title,http.StatusFound)return}renderTemplate(w,"view",p)}funceditHandler(whttp.ResponseWriter,r*http.Request,titlestring){p,err:=loadPage(title)iferr!=nil{p=&Page{Title:title}}renderTemplate(w,"edit",p)}funcsaveHandler(whttp.ResponseWriter,r*http.Request,titlestring){body:=r.FormValue("body")p:=&Page{Title:title,Body:[]byte(body)}err:=p.save()iferr!=nil{http.Error(w,err.Error(),http.StatusInternalServerError)return}http.Redirect(w,r,"/view/"+title,http.StatusFound)}vartemplates=template.Must(template.ParseFiles("edit.html","view.html"))funcrenderTemplate(whttp.ResponseWriter,tmplstring,p*Page){err:=templates.ExecuteTemplate(w,tmpl+".html",p)iferr!=nil{http.Error(w,err.Error(),http.StatusInternalServerError)}}varvalidPath=regexp.MustCompile("^/(edit|save|view)/([a-zA-Z0-9]+)$")funcmakeHandler(fnfunc(http.ResponseWriter,*http.Request,string))http.HandlerFunc{returnfunc(whttp.ResponseWriter,r*http.Request){m:=validPath.FindStringSubmatch(r.URL.Path)ifm==nil{http.NotFound(w,r)return}fn(w,r,m[2])}}funcmain(){http.HandleFunc("/view/",makeHandler(viewHandler))http.HandleFunc("/edit/",makeHandler(editHandler))http.HandleFunc("/save/",makeHandler(saveHandler))log.Fatal(http.ListenAndServe(":8080",nil))}