Go:构建Web Server

一、简单的web server

使用Go创建HTTP服务器,实现一个返回”Hello World!”的web server

1
2
3
4
5
6
7
8
9
10
11
12
13
package main

import (
"fmt"
"net/http"
)

func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello World!")
})
http.ListenAndServe(":80", nil)
}

运行此程序并用浏览器打开到http://localhost,将看到” Hello World!”

二、使用net/http

net/http中主要的三个部分:http.Handler、http.ServeMux、http.server

  • Handler:收到请求后, 进行处理并做出响应
1
2
3
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
  • 路由请求:为确定处理程序对应相应的处理请求,Go使用了HTTP
    multiplexer,根据收到的信息路由到相应的处理程序

  • 处理请求:监听连接,将每个请求发送到路由器,以便可以由正确的程序处理

三、加密

Go中使用HTTPS,如果拥有私钥和证书,可以更改服务器以使用ListenAndServeTLS并提供正确的文件路径

1
http.ListenAndServeTLS(":443", "cert.pem", "key.pem", nil)

打开浏览器,https://example.com将显示“”Hello World!”

四、增加处理

创建通配符路由以及在路由中添加参数或模式匹配。

首先,建一个名为api/router/api.go的文件,其中包含API的路由:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 自定义JSON消息格式
type HelloResponse struct {
Message string `json:"message"`
}

// 返回JSON信息
func HelloName(w http.ResponseWriter, r *http.Request) {
name := chi.URLParam(r, "name")
response := HelloResponse{
Message: fmt.Sprintf("Hello %s!", name),
}
jsonResponse(w, response, http.StatusOK)
}

// 返回一个HTTP处理程序,实现API的路由
func NewRouter() http.Handler {
r := chi.NewRouter()
r.Get("/{name}", HelloName)
return r
}

然后,可以将其挂载到api/router/主应用程序中的前缀下方的主路由器中:

1
2
3
4
5
6
7
// 返回一个新的HTTP处理程序,实现主服务器路由
func NewRouter() http.Handler {
router := chi.NewRouter()
router.Mount("/api/router/", v1.NewRouter())
return router
}
http.Serve(autocert.NewListener("example.com"), NewRouter())

五、中间件

中间件只是将HTTP处理程序包装在另一个处理程序中。这可以实现身份验证,日志记录,压缩等功能。写一些带有处理程序并将其包装在另一个处理程序中的函数。

例如显示了如何实现身份验证处理程序:

1
2
3
4
5
6
7
8
9
10
func RequireAuthentication(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if !isAuthenticated(r) {
http.Redirect(w, r, "/login", http.StatusTemporaryRedirect)
return
}
// 通过了身份验证,请运行原始处理程序
next.ServeHTTP(w, r)
})
}

六、静态文件

Golang的标准库中支持提供静态文件,例如图像,Javascript和样式表。是通过使用函数http.FileServer返回一个处理程序来完成的,该处理程序为目录中的文件提供服务。

简单的路由例子:

1
2
3
4
5
6
7
8
9
10
11
func NewRouter() http.Handler {
router := chi.NewRouter()
r.Get("/{name}", HelloName)

// 设置静态文件
staticPath, _ := filepath.Abs("../../static/")
fs := http.FileServer(http.Dir(staticPath))
router.Handle("/*", fs)

return r
}

七、最后

Go 1.8版本以后引入了通过调用Shutdown()方法正常关闭HTTP服务器的功能。通过在goroutine中启动服务器并在通道上侦听信号中断,使用此功能在收到此消息后,给服务器几秒钟的时间来正常关闭

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
handler := server.NewRouter()
srv := &http.Server{
Handler: handler,
}

go func() {
srv.Serve(autocert.NewListener(domains...))
}()

// 等待中断
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
<-c

// 尝试正常关闭
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
srv.Shutdown(ctx)