目录
我们先来看下在 Go 中创建一个基于 HTTP 协议的 Web 服务是多么的简单。以开发 Web 服务为例,我们可以基于 Go 标准库提供的 net/http 包,轻松构建一个承载 Web 内容传输的 HTTP 服务。
我们来构建一个最简单的 HTTP 服务,这个服务的功能很简单,就是当收到一个 HTTP 请求后,给请求方返回包含“hello, world”数据的响应。
1、准备工作
按下面步骤建立一个 simple-http-server 目录,并创建一个名为 simple-http-server 的 Go Module,执行go mod tidy自动添加依赖。
$ mkdir simple-http-server
$ cd simple-http-server
$ go mod init simple-http-server
$ go mod tidy
因为没有使用到第三方库(只使用了 Go 标准库的 http 包),所以go.mod文件只有如下的内容,所以此时执不执行go mod tidy命令影响不大。
$ cat go.mod
module simple-http-server
go 1.17
用最简项目布局,也就是在 simple-http-server 目录下创建一个 main.go 源文件,代码如下:
package main
import "net/http"
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request){
w.Write([]byte("hello, world"))
})
http.ListenAndServe(":8080", nil)
}
此时目录simple-http-server结构如下:
$ tree
.
├── go.mod
└── main.go
2、编译 && 运行
编译:在simple-http-server 目录下执行如下命令编译:
go build
预期正常情况下会在根目录下生成simple-http-server二进制文件。
运行:
./simple-http-server
测试:
curl localhost:8080/
预期正常情况下会返回hello, world内容。
当然在测试场景下,我们也可以不用编译直接使用go run命令运行程序,如下:
go run main.go
3、简单原理说明
main.go这段代码里,你要注意两个重要的函数,一个是 ListenAndServe,另一个是 HandleFunc。
我们通过 http 包提供的 ListenAndServe 函数,建立起一个 HTTP 服务,这个服务监听本地的 8080 端口。客户端通过这个端口与服务建立连接,发送 HTTP 请求就可以得到相应的响应结果。
那么服务端是如何处理客户端发送的请求的呢?我们看上面代码中的第 6 行。在这一行中,我们为这个服务设置了一个处理函数。这个函数的函数原型是这样的:
func(w http.ResponseWriter, r *http.Request)
这个函数里有两个参数,w 和 r。第二个参数 r 代表来自客户端的 HTTP 请求,第一个参数 w 则是用来操作返回给客户端的应答的,基于 http 包实现的 HTTP 服务的处理函数都要符合这一原型。
你也发现了,在这个例子中,所有来自客户端的请求,无论请求的 URI 路径(RequestURI)是什么,请求都会被我们设置的处理函数处理。为什么会这样呢?这是因为,我们通过 http.HandleFunc 设置这个处理函数时,传入的模式字符串为“/”。HTTP 服务器在收到请求后,会将请求中的 URI 路径与设置的模式字符串进行最长前缀匹配,并执行匹配到的模式字符串所对应的处理函数。在这个例子中,我们仅设置了“/”这一个模式字符串,并且所有请求的 URI 都能与之匹配,自然所有请求都会被我们设置的处理函数处理。