欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

详解Golang开启http服务的三种方式

程序员文章站 2022-03-07 08:46:17
前言都说go标准库实用,api设计简洁。这次就用go 标准库中的net/http包实现一个简洁的http web服务器,包括三种版本。v1最简单版直接使用http.handlefunc(partern...

前言

都说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请求处理。

详解Golang开启http服务的三种方式

handlefunc调用.png

详解Golang开启http服务的三种方式

handlefunc实现handler.png

详解Golang开启http服务的三种方式

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()中有些什么秘密。

详解Golang开启http服务的三种方式

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 将无中断的关闭正在活跃的连接,然后平滑的停止服务。处理流程如下:

  • 首先关闭所有的监听;
  • 然后关闭所有的空闲连接;
  • 然后无限期等待连接处理完毕转为空闲,并关闭;
  • 如果提供了 带有超时的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服务成功:

详解Golang开启http服务的三种方式

成功平滑关闭.png

到此这篇关于详解golang开启http服务的三种方式的文章就介绍到这了,更多相关golang开启http服务内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!