Go学习笔记:写一个简单的web程序
2018-01-10 00:00
906 查看
作为资深Crud Boy,写web算是老本行了,学习了Go的基本语法后,用web练手应该是最佳选择了吧!
官网上给出了一个web的教程,一步步教你如何写出一个简单的web程序。我基本上根据这个教程,又一次熟悉了一下Go的语法,并实现了一个非常非常简单的WEB程序
定义数据结构
比较简单,一个Page结构体,只有标题和内容两个字段
模拟实现数据持久化。
这部分也是简单的一个模拟,将Body部分的数据写入一个txt文件,仅此而已。
实现请求的处理
这部分是这个教程的重点,从最开始简单的响应开始,一步步优化代码,熟悉了异常处理、验证、闭包等语法。
这是最后优化后的三个处理函数。
其中最重要的一个优化是利用闭包,简化了三个处理函数中对于404错误的异常处理
这个函数主要是利用了闭包的特性,理解起来还是比较困难的!Google说闭包是函数式编程的特性,好吧,我的C水平还没达到这么高深的地步=,=
makeHandler的参数是一个函数,就是上面所定义的三个处理函数,返回值也是一个函数,是http的handler函数,这个返回值会在绑定请求时用到。
闭包体现在返回函数中,使用了外部函数的变量fn。
完整的代码如下
说几个过程中遇到的坑:
1、
这段代码中的第二个参数,在使用了templates后,居然不需要加模板文件见面的路径!
2、使用正则做校验时
这个函数的返回值是一个[]string,刚开始以为每个元素都是一个匹配项。后来看到API对这个函数的介绍是
FindStringSubmatch returns a slice of strings holding the text of the leftmost match of the regular expression in s and the matches, if any, of its subexpressions, as defined by the 'Submatch' description in the package comment. A return value of nil indicates no match.
简单说,第一个元素是完全匹配项,后面每一个元素都是一个子匹配项。这个子匹配项还是第一次听说,看了一些文档,感觉go的正则将每一组()当成一个子匹配项。因此前面的例子中,最终返回m[2]才是第二个/后面的内容。
官网上给出了一个web的教程,一步步教你如何写出一个简单的web程序。我基本上根据这个教程,又一次熟悉了一下Go的语法,并实现了一个非常非常简单的WEB程序
定义数据结构
比较简单,一个Page结构体,只有标题和内容两个字段
type Page struct { Title string Body []byte }
模拟实现数据持久化。
这部分也是简单的一个模拟,将Body部分的数据写入一个txt文件,仅此而已。
func (p *Page) save() error { filename := p.Title + ".txt" return ioutil.WriteFile(filename, p.Body, 0600) }
实现请求的处理
这部分是这个教程的重点,从最开始简单的响应开始,一步步优化代码,熟悉了异常处理、验证、闭包等语法。
func viewHandler(w http.ResponseWriter, r *http.Request,title string) { p, err := loadPage(title) if err != nil { http.Redirect(w, r, "/edit/"+title, http.StatusFound) return } renderTemplate(w, "view", p) } func saveHandler(w http.ResponseWriter, r *http.Request,title string) { body := r.FormValue("body") p := Page{Title: title, Body: []byte(body)} err := p.save() if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } http.Redirect(w, r, "/view/"+title, http.StatusFound) } func editHandler(w http.ResponseWriter, r *http.Request,title string) { p, err := loadPage(title) if err != nil { p = &Page{Title: title} } renderTemplate(w, "edit", p) }
这是最后优化后的三个处理函数。
其中最重要的一个优化是利用闭包,简化了三个处理函数中对于404错误的异常处理
func makeHandler(fn func(http.ResponseWriter,*http.Request,string)) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { m := validPath.FindStringSubmatch(r.URL.Path) if m == nil{ http.NotFound(w,r) return } fn(w,r,m[2]) } }
这个函数主要是利用了闭包的特性,理解起来还是比较困难的!Google说闭包是函数式编程的特性,好吧,我的C水平还没达到这么高深的地步=,=
makeHandler的参数是一个函数,就是上面所定义的三个处理函数,返回值也是一个函数,是http的handler函数,这个返回值会在绑定请求时用到。
闭包体现在返回函数中,使用了外部函数的变量fn。
完整的代码如下
package main
import (
"io/ioutil"
"net/http"
"html/template"
"regexp"
)
type Page struct { Title string Body []byte }
var (
templates= template.Must(template.ParseFiles("webapps/edit.html", "webapps/view.html"))
validPath = regexp.MustCompile("^/(edit|save|view)/([a-zA-Z0-9]+)$")
)
func (p *Page) save() error { filename := p.Title + ".txt" return ioutil.WriteFile(filename, p.Body, 0600) }
func loadPage(title string) (*Page, error) {
filename := title + ".txt"
body, err := ioutil.ReadFile(filename)
if (err != nil) {
return nil, err
}
return &Page{title, body}, nil
}
func viewHandler(w http.ResponseWriter, r *http.Request,title string) {
p, err := loadPage(title)
if err != nil {
http.Redirect(w, r, "/edit/"+title, http.StatusFound)
return
}
renderTemplate(w, "view", p)
}
func saveHandler(w http.ResponseWriter, r *http.Request,title string) {
body := r.FormValue("body")
p := Page{Title: title, Body: []byte(body)}
err := p.save()
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
http.Redirect(w, r, "/view/"+title, http.StatusFound)
}
func editHandler(w http.ResponseWriter, r *http.Request,title string) {
p, err := loadPage(title)
if err != nil {
p = &Page{Title: title}
}
renderTemplate(w, "edit", p)//tmpl不包含路径
}
func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {
err := templates.ExecuteTemplate(w, tmpl+".html", p)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
func makeHandler(fn func(http.ResponseWriter,*http.Request,string)) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { m := validPath.FindStringSubmatch(r.URL.Path) if m == nil{ http.NotFound(w,r) return } fn(w,r,m[2]) } }
func main() {
http.HandleFunc("/view/", makeHandler(viewHandler))
http.HandleFunc("/save/", makeHandler(saveHandler))
http.HandleFunc("/edit/", makeHandler(editHandler))
http.ListenAndServe(":8080", nil)
}
说几个过程中遇到的坑:
1、
templates.ExecuteTemplate(w, tmpl+".html", p)
这段代码中的第二个参数,在使用了templates后,居然不需要加模板文件见面的路径!
2、使用正则做校验时
validPath.FindStringSubmatch(r.URL.Path)
这个函数的返回值是一个[]string,刚开始以为每个元素都是一个匹配项。后来看到API对这个函数的介绍是
FindStringSubmatch returns a slice of strings holding the text of the leftmost match of the regular expression in s and the matches, if any, of its subexpressions, as defined by the 'Submatch' description in the package comment. A return value of nil indicates no match.
简单说,第一个元素是完全匹配项,后面每一个元素都是一个子匹配项。这个子匹配项还是第一次听说,看了一些文档,感觉go的正则将每一组()当成一个子匹配项。因此前面的例子中,最终返回m[2]才是第二个/后面的内容。
相关文章推荐
- [shiro学习笔记]第二节 shiro与web融合实现一个简单的授权认证
- C++: wxWidgets (3) 一个简单的wxWidgets程序(学习笔记)
- grails2.2.2学习(二)一个简单的web程序
- [shiro学习笔记]第二节 shiro与web融合实现一个简单的授权认证
- 网络编程学习笔记二(实现一个基于简单TCP的用户注册程序)
- [shiro学习笔记]第二节 shiro与web融合实现一个简单的授权认证
- OpenCV 2 学习笔记(3): 一个简单的opencv程序:在Console上显示图像
- Servlet学习笔记_03_使用servlet编写一个简单的helloworld程序
- 基于node的websocket学习笔记二:一个简单的聊天室程序与优化方案
- 学习 UNIX网络编程卷1:套接字 笔记1-实现一个简单的回射客户服务器程序
- 微信小程序,学习笔记(二)样式(WXSS)及一个简单的小测试用例
- linux0.11学习笔记-技术铺垫-简单AB任务切换程序(1)-实现一个简单的bootloader
- Spring boot 学习笔记 ---分分钟构建一个web程序(一)
- 整理一下当年的学习笔记之:初步学习freemarker ,先做一个简单的HelloWord程序!
- 32位汇编语言学习笔记(28)--一个简单的光标控制程序
- JVM学习笔记——一个简单程序编译成字节码指令后的解释
- 黑马程序员--学习笔记--一个WinForm简单加法练习程序
- 【opencv学习笔记五】一个简单程序:图像读取与显示
- 【UNP学习笔记】一个简单的服务器/客户端程序
- UNIX环境编程学习笔记-----编程实例------一个简单的服务器端和客户端程序