62

Golang开启http服务的三种方式

 5 years ago
source link: https://studygolang.com/articles/15283?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

前言

都说go标准库实用,Api设计简洁。这次就用go 标准库中的net/http包实现一个简洁的http web服务器,包括三种版本。

v1最简单版

直接使用http.HandleFunc(partern,function(http.ResponseWriter,

*http.Request){})

HandleFunc接受两个参数,第一个为路由地址,第二个为处理方法。

//v1
func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
         w.Write([]byte("httpserver v1"))
       })
       http.HandleFunc("/bye", sayBye)
       log.Println("Starting v1 server ...")
       log.Fatal(http.ListenAndServe(":1210", nil))
 }

func sayBye(w http.ResponseWriter, r *http.Request) {
      w.Write([]byte("bye bye ,this is v1 httpServer"))
}

v2自定义Handler

查看标准库源码,v1版本实际上是调用了handle方法,传入的HandlerFunc实现了Handler的ServeHTTP方法,实际上是ServeHTTP在做http请求处理。

fuURj2z.png!web

HandleFunc调用.png

YNbQBbe.png!web

HandleFunc实现Handler.png

yyEnI3B.png!web

Handler接口定义.png

由此我们可以自定义自己的Handler,v2版本代码如下:

// v2
func main() {
   mux := http.NewServeMux()
   mux.Handle("/", &myHandler{})
   mux.HandleFunc("/bye", sayBye)

   log.Println("Starting v2 httpserver")
   log.Fatal(http.ListenAndServe(":1210", mux))
}
type myHandler struct{}

func (*myHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
      w.Write([]byte("this is version 2"))
}
func sayBye(w http.ResponseWriter, r *http.Request) {
     w.Write([]byte("bye bye ,this is v2 httpServer"))
}

v3自定义server配置

前面对Handler开了一次刀,下面我们看看http.ListenAndServe()中有些什么秘密。

n2q6ziU.png!web

ListenAndServe.png

原来这里可以自定义http服务器配置,都在Server这个结构体中,这个对象能配置监听地址端口,配置读写超时时间,配置handler,配置请求头最大字节数...,所有稍微改造一下v2的程序得到v3版:

// v3
func main() {
    mux := http.NewServeMux()
    mux.Handle("/", &myHandler{})
    mux.HandleFunc("/bye", sayBye)

    server := &http.Server{
        Addr:         ":1210",
        WriteTimeout: time.Second * 3,            //设置3秒的写超时
        Handler:      mux,
    }
    log.Println("Starting v3 httpserver")
    log.Fatal(server.ListenAndServe())
}

type myHandler struct{}

func (*myHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("this is version 3"))
}

func sayBye(w http.ResponseWriter, r *http.Request) {
       // 睡眠4秒  上面配置了3秒写超时,所以访问 “/bye“路由会出现没有响应的现象
    time.Sleep(4 * time.Second)              
    w.Write([]byte("bye bye ,this is v3 httpServer"))
}

拓展一下(如何平滑关闭http服务)

在go1.8中新增了一个新特性,利用Shutdown(ctx context.Context) 优雅地关闭http服务。

文档中描述:

Shutdown 将无中断的关闭正在活跃的连接,然后平滑的停止服务。处理流程如下:

  1. 首先关闭所有的监听;
  2. 然后关闭所有的空闲连接;
  3. 然后无限期等待连接处理完毕转为空闲,并关闭;
  4. 如果提供了 带有超时的Context,将在服务关闭前返回 Context的超时错误;

利用这个特性改造一下v3版本的程序,实现一个关闭http的提示

// 主动关闭服务器
var server *http.Server
func main() {
    
 // 一个通知退出的chan
quit := make(chan os.Signal)
signal.Notify(quit, os.Interrupt)

mux := http.NewServeMux()
mux.Handle("/", &myHandler{})
mux.HandleFunc("/bye", sayBye)

server = &http.Server{
    Addr:         ":1210",
    WriteTimeout: time.Second * 4,
    Handler:      mux,
}

go func() {
    // 接收退出信号
    <-quit
    if err := server.Close(); err != nil {
        log.Fatal("Close server:", err)
    }
}()

log.Println("Starting v3 httpserver")
err := server.ListenAndServe()
if err != nil {
    // 正常退出
    if err == http.ErrServerClosed {
        log.Fatal("Server closed under request")
    } else {
        log.Fatal("Server closed unexpected", err)
    }
}
  log.Fatal("Server exited")

}

type myHandler struct{}

func (*myHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  w.Write([]byte("this is version 3"))
}

 // 关闭http
func sayBye(w http.ResponseWriter, r *http.Request) {
      w.Write([]byte("bye bye ,shutdown the server"))     // 没有输出
      err := server.Shutdown(nil)
      if err != nil {
        log.([]byte("shutdown the server err"))
      }
 }

尝试访问 http://localhost:1210/bye 在控制台会得到以下提示结果,平滑关闭http服务成功:

buyie2j.png!web

成功平滑关闭.png


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK