GO语言(十九)编写Web应用程序(上)
介绍
本教程涵盖: 创建具有加载和保存方法的数据结构 使用该net/http包构建 Web 应用程序 使用html/template包处理 HTML 模板 使用regexp包验证用户输入 使用闭包
需要知识: 编程经验 了解基本的网络技术(HTTP、HTML) 一些 UNIX/DOS 命令行知识
入门
目前,您需要有一台 FreeBSD、Linux、macOS 或 Windows 机器来运行 Go。
在你的GOPATH和 cd 中为本教程创建一个新目录: $ mkdir gowiki $ cd gowiki
创建一个名为 的文件wiki.go,在您喜欢的编辑器中打开它,然后添加以下行: package main import ( "fmt" "os" )
我们从 Go 标准库中 导入fmt和os包。稍后,当我们实现附加功能时,我们将在此import声明中添加更多包。
数据结构
让我们从定义数据结构开始。一个 wiki 由一系列相互关联的页面组成,每个页面都有一个标题和一个正文(页面内容)。在这里,我们定义Page为一个结构体,其中包含两个字段,分别代表标题和正文。 type Page struct { Title string Body []byte }
该类型的[]byte意思是byte切片。Body元素是 []byte类型而不是 string类型,因为这是 我们将使用的io库所期望的类型。
该Page结构描述了页面数据将如何存储在内存中。但是持久存储呢?我们可以通过在 上创建一个 save方法来解决这个问题Page: func (p *Page) save() error { filename := p.Title + ".txt" return os.WriteFile(filename, p.Body, 0600) }
这是一个名为save的方法,它的接收者p是一个指向的指针Page。它不接受任何参数,并返回一个error类型的值。
此方法会将Page"s保存Body到文本文件中。为简单起见,我们将使用Title作为文件名。
该save方法返回一个error值,因为这是WriteFile(将字节切片写入文件的标准库函数)的返回类型。该save方法返回错误值,让应用程序在写入文件时出现任何问题时处理它。如果一切顺利,Page.save()将返回 nil(指针、接口和其他一些类型的零值)。
八进制整数文字0600,作为第三个参数传递给 WriteFile,表示创建文件时应仅对当前用户具有读写权限。
除了保存页面,我们还需要加载页面: func loadPage(title string) *Page { filename := title + ".txt" body, _ := os.ReadFile(filename) return &Page{Title: title, Body: body} }
该loadPage函数从 title 参数构造文件名,将文件的内容读入一个新变量body,并返回一个指向Page由正确的标题和正文值构造的文字的指针。
函数可以返回多个值。标准库函数 os.ReadFile返回[]byte和error。在loadPage中,尚未处理错误;下划线 ( ) 符号表示的"空白标识符"_用于丢弃错误返回值(本质上,将值赋值为空)。
但是如果ReadFile遇到错误会发生什么?例如,该文件可能不存在。我们不应该忽视这样的错误。让我们修改函数以返回*Page和error。 func loadPage(title string) (*Page, error) { filename := title + ".txt" body, err := os.ReadFile(filename) if err != nil { return nil, err } return &Page{Title: title, Body: body}, nil }
该函数的调用者现在可以检查第二个参数;如果是, nil则它已成功加载页面。如果不是,它将是可以由调用者处理的error。
现在,我们有一个简单的数据结构和保存到文件以及从文件加载的能力。让我们编写一个main函数来测试我们所写的内容: func main() { p1 := &Page{Title: "TestPage", Body: []byte("This is a sample Page.")} p1.save() p2, _ := loadPage("TestPage") fmt.Println(string(p2.Body)) }
编译并执行此代码后,将创建一个名为的文件TestPage.txt ,其中包含p1. 然后将文件读入 struct p2,并将其Body元素打印到屏幕上。
您可以像这样编译和运行程序: $ go build wiki.go $ ./wiki This is a sample Page.
介绍net/http包装
这是一个简单 Web 服务器的完整工作示例: //go:build ignore package main import ( "fmt" "log" "net/http" ) func handler(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:]) } func main() { http.HandleFunc("/", handler) log.Fatal(http.ListenAndServe(":8080", nil)) }
该main函数以对http.HandleFunc 的调用开始 ,它告诉http包使用handler处理对 Web 根 "/"的所有请求。
然后它调用http.ListenAndServe,指定它应该在任何接口 ( ":8080") 上侦听端口 8080。(暂时不要担心它的第二个参数nil。)这个函数将一直阻塞,直到程序终止。
ListenAndServe总是返回一个错误,因为它只在发生意外错误时返回。为了记录该错误,我们将函数调用用log.Fatal.
handler函数的类型为http.HandlerFunc。它以 http.ResponseWriter和 anhttp.Request作为参数。
http.ResponseWriter值组合了 HTTP 服务器的响应;通过写入它,我们将数据发送到 HTTP 客户端。
http.Request是表示客户端 HTTP 请求的数据结构。r.URL.Path是请求 URL 的路径组件。 [1:] 意味着"创建从第一个字符到结尾的子切片"。
如果您运行此程序并访问 URL: http://localhost:8080/monkeys
该程序将显示一个页面,其中包含: Hi there, I love monkeys!
使用net/http包创建wiki页面
要使用net/http包,必须将其导入: import ( "fmt" "os" "log" "net/http" )
让我们创建一个处理程序,viewHandler它允许用户查看 wiki 页面。它将处理以"/view/"为前缀的 URL。 func viewHandler(w http.ResponseWriter, r *http.Request) { title := r.URL.Path[len("/view/"):] p, _ := loadPage(title) fmt.Fprintf(w, "%s
%s", p.Title, p.Body) }
再次注意使用_忽略error 来自loadPage的返回值。这是为了简单起见,通常被认为是不好的做法。我们稍后会处理这个问题。
首先,此函数从请求 URL 的路径组件r.URL.Path中提取页面标题。Path重新切片以删除请求路径的前导"/view/"。这是因为路径总是以"/view/"开头,它不是页面标题的一部分。
然后该函数加载页面数据,用一串简单的 HTML 格式化页面,并将其w写入http.ResponseWriter.
要使用这个处理程序,我们重写我们的main函数来使用viewHandler处理/view/路径下的任何请求。 func main() { http.HandleFunc("/view/", viewHandler) log.Fatal(http.ListenAndServe(":8080", nil)) }
让我们创建一些页面数据,编译我们的代码,并尝试提供一个 wiki 页面。
在编辑器中打开test.txt文件,并在其中保存字符串"Hello world"(不带引号)。 $ go build wiki.go $ ./wiki
随着这个网络服务器的运行,访问http://localhost:8080/view/test 应该会显示一个标题为"test"的页面,其中包含"Hello world"这个词。
世界级数学家拉福格加入华为后首度亮相,同事中还有多位菲尔兹奖得主12月6日,华为法国在社交媒体上发布了法国数学家数学最高奖菲尔兹奖得主洛朗拉福格(LaurentLafforgue)的视频采访。今年9月加入华为巴黎研究所的拉福格在视频中表示加入华
国产手机中,真正用心做手机的有哪些品牌?在国产手机中,真正用心做手机的品牌有哪些?可能十个人里面就有十个不同的品牌,那么我来谈谈我心目中,现如今真正用心用手机的品牌。很多人可能会说是华为手机,这点我不否认,但是我认为真正
人民日报评元宇宙炒房热到烫伤的风险得防近期,国内外兴起了一阵元宇宙炒房热。买地皮,买房屋,买物料,搞装修,等升值,再出售虚拟房地产买卖,伴随元宇宙概念火了起来。这是新现象,也还处在发展的最初阶段,是投机还是投资是泡沫还
人民日报专版发文谈企业家精神,释放什么信号?联想问题讨论已有定论,我们国家及人民需要的是有企业家精神的真正企业家,那种披着所谓企业家外衣,行资本家行径的狼,必将受到应有的惩罚!大家试目以待!什么是企业家?什么是资本家?什么是
又涨价了!骁龙8Gen1机型4K以上才能买到,苹果或成最大受益者今晚摩托罗拉将召开新品发布会,正式推出motoedgeX30机型,该款新机将搭载高通骁龙8Gen1旗舰处理器,这将是你能最快买到的骁龙8Gen1机型。至于售价,虽然官方从未提及这方
关于童年的记忆,你最有印象的是什么?童年的记忆是模糊的,虽然模糊,但那份由小小的电视带来的欢乐至今还记得清晰。我是80后,出生于北方的小城泰安,那时在城里电视机已经基本普及了。我家的是一台14吋的黑白电视机,牌子已经
现在的电视机真的智能吗?人工智能还是人工智障?目前很多智能电视都是采用了定制版安卓系统和定制电视芯片,由于系统非常臃肿,系统优化较差,硬件配置较低,很多电视都带有开机广告,而且内部广告也非常多,不但开机速度慢,而且系统流畅度表
5G消息商用渐行渐近产业链龙头受关注近期,5G消息商用迎来新进展。运营商方面,5G消息试商用渐次推出,终端推进与应用生态构建不断加速,产业链上龙头企业也在提前布局。机构认为,5G消息商用将给行业带来新机遇,C端(个人
准备一部备用机好还是直接用双卡手机更好?我个人认为一部双卡双待手机和两部手机是完全不同的两种使用体验。我自己也使用两部手机,而且一直使用了很多年,大概有十年的时间,我一直使用两部手机。下面说说我的认为的区别在哪里。手机系
资金型合伙人都是魔鬼,不信就看看俏江南的结局刘强东从来不相信投资人,所以投资人对这位京东掌门人也是既爱又恨。这其实应该成为合伙企业的常态相爱相杀,从冤家熬到亲家!上海文峰秘书夸总裁有天眼在创始人与资金型合伙人双方控制权的博弈
还在用相机直接拍?这样调让你拍出大片既视感手机拍摄常用的参数介绍像素就是手机参数当中介绍的手机像素,但是,不能单纯的依据像素的高低来评价手机的拍照质量,除了像素外,衡量手机拍照质量的的因素还有感光原件以及手机的系统算法方面