《Go Web编程》之ChitChat论坛(文末赠书)

本文主要内容

  • 使用Go进行Web编程的方法
  • 设计一个典型的Go Web应用
  • 编写一个完整的Go Web应用
  • 了解Go Web应用的各个组成部分

本文我们将会构建一个简单的网上论坛Web应用,这个应用同样非常基础,但是却有用得多:它允许用户登录到论坛里面,然后在论坛上发布新帖子,又或者回复其他用户发表的帖子。在阅读完这一文之后,你将进一步地了解到使用Go进行Web应用开发的相关方法。

ChitChat简介

网上论坛无处不在,它们是互联网上最受欢迎的应用之一,与旧式的电子公告栏(BBS)、新闻组(Usenet)和电子邮件一脉相承。雅虎公司和Google公司的群组(Groups)都非常流行,雅虎报告称,他们总共拥有1000万个群组以及1.15亿个群组成员,其中每个群组都拥有一个自己的论坛;而全球最具人气的网上论坛之一——Gaia在线——则拥有2300万注册用户以及接近230亿张帖子,并且这些帖子的数量还在以每天上百万张的速度持续增长。尽管现在出现了诸如Facebook这样的社交网站,但论坛仍然是人们在网上进行交流时最为常用的手段之一。作为例子,图1展示了GoogleGroups的样子。

图1 一个网上论坛示例:GoogleGroups里面的Go编程语言论坛

从本质上来说,网上论坛就相当于一个任何人都可以通过发帖来进行对话的公告板,公告板上面可以包含已注册用户以及未注册的匿名用户。论坛上的对话称为帖子(thread),一个帖子通常包含了作者想要讨论的一个主题,而其他用户则可以通过回复这个帖子来参与对话。比较复杂的论坛一般都会按层级进行划分,在这些论坛里面,可能会有多个讨论特定类型主题的子论坛存在。大多数论坛都会由一个或多个拥有特殊权限的用户进行管理,这些拥有特殊权限的用户被称为版主(moderator)。

在本文中,我们将会开发一个名为ChitChat的简易网上论坛。为了让这个例子保持简单,我们只会为ChitChat实现网上论坛的关键特性:在这个论坛里面,用户可以注册账号,并在登录之后发表新帖子又或者回复已有的帖子;未注册用户可以查看帖子,但是无法发表帖子或是回复帖子。现在,让我们首先来思考一下如何设计ChitChat这个应用。

应用设计

Web应用的一般工作流程是客户端向服务器发送请求,然后服务器对客户端进行响应(如图2所示),ChitChat应用的设计也遵循这一流程。

图2 Web应用的一般工作流程,客户端向服务器发送请求,然后等待接收响应

ChitChat的应用逻辑会被编码到服务器里面。服务器会向客户端提供HTML页面,并通过页面的超链接向客户端表明请求的格式以及被请求的数据,而客户端则会在发送请求时向服务器提供相应的数据,如图3所示。

图3 HTTP请求的URL格式

请求的格式通常是由应用自行决定的,比如,ChitChat的请求使用的是以下格式:http://<服务器名><处理器名>?<参数>

服务器名(server name)是ChitChat服务器的名字,而处理器名(handler name)则是被调用的处理器的名字。处理器的名字是按层级进行划分的:位于名字最开头是被调用模块的名字,而之后跟着的则是被调用子模块的名字,以此类推,位于处理器名字最末尾的则是子模块中负责处理请求的处理器。比如,对/thread/read这个处理器名字来说,thread是被调用的模块,而read则是这个模块中负责读取帖子内容的处理器。

该应用的参数(parameter)会以URL查询的形式传递给处理器,而处理器则会根据这些参数对请求进行处理。比如说,假设客户端要向处理器传递帖子的唯一ID,那么它可以将URL的参数部分设置成id=123,其中123就是帖子的唯一ID。

如果chitchat就是ChitChat服务器的名字,那么根据上面介绍的URL格式规则,客户端发送给ChitChat服务器的URL可能会是这样的:http://chitchat/thread/read?id=123。

当请求到达服务器时,多路复用器(multiplexer)会对请求进行检查,并将请求重定向至正确的处理器进行处理。处理器在接收到多路复用器转发的请求之后,会从请求中取出相应的信息,并根据这些信息对请求进行处理。在请求处理完毕之后,处理器会将所得的数据传递给模板引擎,而模板引擎则会根据这些数据生成将要返回给客户端的HTML,整个过程如图4所示。

图4 服务器在典型Web应用中的工作流程

数据模型

绝大多数应用都需要以某种方式与数据打交道。对ChitChat来说,它的数据将被存储到关系式数据库PostgreSQL里面,并通过SQL与之交互。

ChitChat的数据模型非常简单,只包含4种数据结构,它们分别是:

  • User——表示论坛的用户信息;
  • Session——表示论坛用户当前的登录会话;
  • Thread——表示论坛里面的帖子,每一个帖子都记录了多个论坛用户之间的对话;
  • Post——表示用户在帖子里面添加的回复。

以上这4种数据结构都会被映射到关系数据库里面,图5展示了这4种数据结构是如何与数据库交互的。

ChitChat论坛允许用户在登录之后发布新帖子或者回复已有的帖子,未登录的用户可以阅读帖子,但是不能发布新帖子或者回复帖子。为了对应用进行简化,ChitChat论坛没有设置版主这一职位,因此用户在发布新帖子或者添加新回复的时候不需要经过审核。

图5 Web应用访问数据存储系统的流程

在了解了ChitChat的设计方案之后,现在可以开始考虑具体的实现代码了。在开始学习ChitChat的实现代码之前,请注意,如果你在阅读本章展示的代码时遇到困难,又或者你是刚开始学习Go语言,那么为了更好地理解本章介绍的内容,你可以考虑先花些时间阅读一本Go语言的编程入门书,比如,由William Kennedy、Brian Ketelsen和Erik St. Martin撰写的《Go语言实战》就是一个很不错的选择。

除此之外,在阅读本章时也请尽量保持耐性:本章只是从宏观的角度展示Go Web应用的样子,并没有对Web应用的细节作过多的解释,而是将这些细节留到之后的章节再进一步说明。在有需要的情况下,本章也会在介绍某种技术的同时,说明在哪一章可以找到这一技术的更多相关信息。

请求的接收与处理

请求的接收和处理是所有Web应用的核心。正如之前所说,Web应用的工作流程如下。

(1)客户端将请求发送到服务器的一个URL上。

(2)服务器的多路复用器将接收到的请求重定向到正确的处理器,然后由该处理器对请求进行处理。

(3)处理器处理请求并执行必要的动作。

(4)处理器调用模板引擎,生成相应的HTML并将其返回给客户端。

让我们先从最基本的根URL(/)来考虑Web应用是如何处理请求的:当我们在浏览器上输入地址http://localhost的时候,浏览器访问的就是应用的根URL。在接下来的几个小节里面,我们将会看到ChitChat是如何处理发送至根URL的请求的,以及它又是如何通过动态地生成HTML来对请求进行响应的。

1 多路复用器

因为编译后的二进制Go应用总是以main函数作为执行的起点,所以我们在对Go应用进行介绍的时候也总是从包含main函数的主源码文件(main source code file)开始。ChitChat应用的主源码文件为main.go,代码清单1展示了它的一个简化版本。

代码清单1 main.go文件中的main函数,函数中的代码经过了简化


package main
import (
"net/http"
)
func main() {
mux := http.NewServeMux()
files := http.FileServer(http.Dir("/public"))
mux.Handle("/static/", http.StripPrefix("/static/", files))
mux.HandleFunc("/", index)
server := &http.Server{
Addr: "0.0.0.0:8080",
Handler: mux,
}
server.ListenAndServe()
}

main.go``中``首先创建了一个多路复用器,然后通过一些代码将接收到的请求重定向到处理器。net/http标准库提供了一个默认的多路复用器,这个多路复用器可以通过调用NewServeMux函数来创建:


mux := http.NewServeMux()

为了将发送至根URL的请求重定向到处理器,程序使用了HandleFunc函数:


mux.HandleFunc("/", index)

HandleFunc函数接受一个URL和一个处理器的名字作为参数,并将针对给定URL的请求转发至指定的处理器进行处理,因此对上述调用来说,当有针对根URL的请求到达时,该请求就会被重定向到名为index的处理器函数。此外,因为所有处理器都接受一个ResponseWriter和一个指向Request结构的指针作为参数,并且所有请求参数都可以通过访问Request结构得到,所以程序并不需要向处理器显式地传入任何请求参数。

需要注意的是,前面的介绍模糊了处理器以及处理器函数之间的区别:我们刚开始谈论的是处理器,而现在谈论的却是处理器函数。这是有意而为之的——尽管处理器和处理器函数提供的最终结果是一样的,但它们实际上并不相同。本书的第3章将对处理器和处理器函数之间的区别做进一步的说明,但是现在让我们暂时先忘掉这件事,继续研究ChitChat应用的代码实现。

2 服务静态文件

除负责将请求重定向到相应的处理器之外,多路复用器还需要为静态文件提供服务。为了做到这一点,程序使用FileServer函数创建了一个能够为指定目录中的静态文件服务的处理器,并将这个处理器传递给了多路复用器的Handle函数。除此之外,程序还使用StripPrefix函数去移除请求URL中的指定前缀:


files := http.FileServer(http.Dir("/public"))
mux.Handle("/static/", http.StripPrefix("/static/", files))

当服务器接收到一个以/static/开头的URL请求时,以上两行代码会移除URL中的/static/字符串,然后在public目录中查找被请求的文件。比如说,当服务器接收到一个针对文件http://localhost/static/css/bootstrap.min.css的请求时,它将会在public目录中查找以下文件:


<application root>/css/bootstrap.min.css

当服务器成功地找到这个文件之后,会把它返回给客户端。

3 创建处理器函数

正如之前的小节所说,ChitChat应用会通过HandleFunc函数把请求重定向到处理器函数。正如代码清单2所示,处理器函数实际上就是一个接受ResponseWriterRequest指针作为参数的Go函数。

代码清单2 main.go文件中的index处理器函数


func index(w http.ResponseWriter, r *http.Request) {
files := []string{"templates/layout.html",
"templates/navbar.html",
"templates/index.html",}
templates := template.Must(template.ParseFiles(files...))
threads, err := data.Threads(); if err == nil {
templates.ExecuteTemplate(w, "layout", threads)
}
}

index函数负责生成HTML并将其写入ResponseWriter中。因为这个处理器函数会用到html/template标准库中的Template结构,所以包含这个函数的文件需  要在文件的开头导入html/template库。之后的小节将对生成HTML的方法做进一步的介绍。

除了前面提到过的负责处理根URL请求的index处理器函数,main.go文件实际上还包含很多其他的处理器函数,如代码清单3所示。

代码清单3 ChitChat应用的main.go源文件


package main
import (
"net/http"

时间: 2024-08-26 18:15:49

《Go Web编程》之ChitChat论坛(文末赠书)的相关文章

杨彪 | 一次线上游戏卡死的解决历程(文末赠书福利)

题图:StartupStock@Pixabay 编辑:冷锋 作者:杨彪 本文首发于简书云时代构架杨彪 http://www.jianshu.com/p/7885bbf153f5 事故的发生详细过程 故事是发生在几个月前的线上真实案例,我将在本文中以故事形式为大家还原这次解决游戏卡死的经历过程,其中有很多线上实战经验和技巧都值得分享借鉴的,也有作者自创的处理线上问题"四部曲"--望问闻切,还有最经典的"甩锅"秘诀. 不管白猫黑猫,能立马解决线上问题的就是好猫,线上问题

Java编程中更新XML文档的常用方法

xml|编程 本文简要的讨论了Java语言编程中更新XML文档的四种常用方法,并且分析这四种方法的优劣.其次,本文还对如何控制Java程序输出的XML文档的格式做了展开论述. JAXP是Java API for XML Processing的英文字头缩写,中文含义是:用于XML文档处理的使用Java语言编写的编程接口.JAXP支持DOM.SAX.XSLT等标准.为了增强JAXP使用上的灵活性,开发者特别为JAXP设计了一个Pluggability Layer,在Pluggability Laye

教你如何使用JSP面向对象web编程技术实现树形控件

js|web|编程|对象|控件 树形控件是一种人们熟悉的用户界面控件,广泛地用来显示层次型数据. 树形控件具有独特的扩展和折叠分支的能力,能够以较小的空间显示出大量的信息,一目了然地传达出数据之间的层次关系.凡是熟悉图形用户界面的用户,都能够自如地运用树形控件. 图一:用java script实现的树形控件 HTML本身不支持树形控件,但我们可以通过一些java script脚本代码实现.为了提高控件的可重用性,我们要充分运用java script对面向对象编程技术的支持.本文的树形控件适用于I

所有编程皆为 Web 编程

Michael Braude对Web编程大受追捧表达了他的不屑: 大部分人想去做Web编程的原因是,他们不够聪明,因此也做不了别的事. 他们不懂编译器.并发性.3D或类继承.他们根本不明白我为什么要使用接口或者抽象类.他们不理解虚函数.指针.引用.垃圾回收.终结器.传引用与传值的 区别.C++的虚拟析构函数.或者C#的结构体与类之间的差别.他们对进程也一无所知.更别提瀑布.螺旋.敏捷了!他们从来没看过需求文档,也从来没写过 设计文档:他们从没画过一张UML图,甚至听都没听说过有"顺序图"

Angular的12个经典问题,看看你能答对几个?(文末附带Angular测试)

Angular作为目前最为流行的前端框架,受到了前端开发者的普遍欢迎.不论是初学Angular的新手,还是有一定Angular开发经验的开发者,了解本文中的12个经典面试问题,都将会是一个深入了解和学习Angular 2的知识概念的绝佳途径. 在文中,我们将会接触到很多Angular 2的重要概念,并附扩展阅读资料和自查小测试,供大家评估自己对Angular的了解程度.   Angular 经典问题及扩展阅读 1.  请解释Angular 2应用程序的生命周期hooks是什么? Angular

WEB编程开发常用的代码

web|编程  1. ASP与Access数据库连接: dim conn,mdbfile  mdbfile=server.mappath("数据库名称.mdb")  set conn=server.createobject("adodb.connection")  'conn.open "driver={microsoft access driver (*.mdb)};uid=admin;pwd=数据库密码;dbq="&mdbfileco

使用WCF的Web编程模型开发REST风格的Web Service

WCF中的Web编程模型提供了一种以REST风格来设计Web Service的功能,它不同于以往基于SOAP或者WS-*规范的Web Service,而是以URI和http协议为中心的.对于操作的每一个资源有唯一的标志符,而利用不同的http动作(例如GET,POST,PUT,DELETE)来对这些资源进行相应的操作.同时该模型中还提供URI Template,它是用来定义参数化的URI,使URI的某些部分作为参数在服务中使用.可能这样解释十分含糊不清,下面用一个小例子来说明这种Web编程模型.

集大成之作 | 《尽在双11:阿里巴巴技术演进与超越》重磅预售!(文末有福利)

春暖花开之际,<尽在双11:阿里巴巴技术演进与超越>终于正式与大家见面了.此书前所未有地汇聚了阿里全体技术人的智慧,被阿里巴巴集团CTO行癫盛赞为"迄今为止对双11技术演进最客观.最详实的还原."  购买方式:淘宝天猫预售地址(文末有福利,看完再买享优惠) 在线试读:https://yq.aliyun.com/books/4295 技无止境,双十一技术进化史   2009年,双十一诞生.当时,整个技术部门只有几个人被临时安排值班,高峰每秒只有400个请求.  8年之后,双十

asp.net WEB编程 如果获取剪切板里的多条数据复制到gridview中?

问题描述 先从excel表中复制多条数据,再把这些数据粘贴到gridview中!web编程引用不了system.window.form! 解决方案 解决方案二:最好有实例!自己顶一下!!解决方案三:up...............解决方案四:如果是web的话,你需要先把excel文件上传到服务器,然后在读取这个文件....