| by suyi | No comments

Go:构建Web Server

一、简单的web server

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

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:收到请求后, 进行处理并做出响应
type Handler interface {
        ServeHTTP(ResponseWriter, *Request)
}
  • 路由请求:为确定处理程序对应相应的处理请求,Go使用了HTTP
    multiplexer,根据收到的信息路由到相应的处理程序
  • 处理请求:监听连接,将每个请求发送到路由器,以便可以由正确的程序处理

三、加密

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

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

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

四、增加处理

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

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

// 自定义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/主应用程序中的前缀下方的主路由器中:

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

五、中间件

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

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

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返回一个处理程序来完成的,该处理程序为目录中的文件提供服务。

简单的路由例子:

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中启动服务器并在通道上侦听信号中断,使用此功能在收到此消息后,给服务器几秒钟的时间来正常关闭

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)

发表评论