这里开始之前,先来说说golang中http服务的内部机制(所有其他库都是在此基础延伸)
这里开始之前,先来说说golang中http服务中三个重要的方法(所有其他库都是在此基础延伸)
- func Handle
- func Handle(pattern string, handler Handler)
Handle registers the handler for the given pattern in the DefaultServeMux. The documentation for ServeMux explains how patterns are matched.
- func Handle(pattern string, handler Handler)
- func HandleFunc
- func HandleFunc(pattern string, handler func(ResponseWriter, *Request))
HandleFunc registers the handler function for the given pattern in the DefaultServeMux. The documentation for ServeMux explains how patterns are matched.
- func HandleFunc(pattern string, handler func(ResponseWriter, *Request))
- func ListenAndServe
- func ListenAndServe(addr string, handler Handler) error
ListenAndServe listens on the TCP network address addr and then calls Serve with handler to handle requests on incoming connections. Handler is typically nil, in which case the DefaultServeMux is used.
- func ListenAndServe(addr string, handler Handler) error
注意:
ListenAndServe是用于在指定的TCP 网络地址addr 进行监听,然后调用服务端处理程序来处理传入的连
接请求。该方法有两个参数:第一个参数addr 即监听地址;第二个参数表示服务端处理程序,
通常为空,这意味着服务端调用 http.DefaultServeMux 进行处理,而服务端编写的业务逻
辑处理程序 http.Handle() 或 http.HandleFunc() 默认注入 http.DefaultServeMux 中
下面以三种不同的方式实现最Golang中基本的Http Server
默认方式
默认handler,处理路由注册
//===================================Http 1===================================//
func Http_Server1() {
http.HandleFunc("/", sayServer1)
err := http.ListenAndServe(":8080", nil)
if err != nil {
panic(err)
}
}
func sayServer1(w http.ResponseWriter, r *http.Request) {
io.WriteString(w,"sayServer1 Http Service")
}
自定义方式
自己实现hander,注册到max中,在注册路由
//===================================Http 2===================================//
func Http_Server2() {
mux := http.NewServeMux()
mux.Handle("/", &myHanlder{})
mux.HandleFunc("/hello", sayServer2)
err := http.ListenAndServe(":8080", mux)
if err != nil {
panic(err)
}
}
type myHanlder struct{}
func (*myHanlder) ServeHTTP(w http.ResponseWriter, r *http.Request) {
io.WriteString(w,"Http Service: "+ r.URL.String())
}
func sayServer2(w http.ResponseWriter, r *http.Request) {
io.WriteString(w,"sayServer2 Http Service")
}
底层拓展方式
底层实现路由注册,多用户封装
//===================================Http 3===================================//
var mux map[string]func(http.ResponseWriter, *http.Request) // 路由指定
func Http_Server3() {
server := http.Server{
Addr:":8080",
Handler:&mHandler{},
ReadTimeout:5*time.Second,
}
注册
mux = make(map[string]func(http.ResponseWriter, *http.Request))
mux["/hello"] = sayServer3
mux["/golang"] = golang
err := server.ListenAndServe()
if err != nil {
panic(err)
}
}
type mHandler struct {}
func (*mHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if h,ok := mux[r.URL.String()]; ok {
h(w,r)
return
}
io.WriteString(w,"Http Service Custome: "+ r.URL.String())
}
func sayServer3(w http.ResponseWriter, r *http.Request) {
io.WriteString(w,"sayServer3 Http Service")
}
func golang(w http.ResponseWriter, r *http.Request) {
io.WriteString(w,"golang Http Service")
}
Beego你好世界
其实上面只是作为个简单的入门了解,一般实际开发中,那么做的还是不多,我们大部分都会选择使用第三方,比如PHP中的ThinkPHP,Yii,在Golang中也有几个不错的第三个可以使用,而且目前已经很成熟了,至少可以满足目前几乎大部分公司的业务需求
比如beego(国人开发),gin,dotweb,echo这些都是笔者通过技术群或者网络热门程度了解到在Golang中还不错的的库,而且使用中和非常多。
这里我简单以beego作为案例尝试下,没有什么技术含量,勿喷
下载安装(前提:配置GOPATH)
go get github.com/astaxie/beego
创建文件 hello.go
//================================Hello World!!===============================//
package main
import "github.com/astaxie/beego"
type HomeController struct {
beego.Controller
}
func (this *HomeController) Get() {
this.Ctx.WriteString("Hello World!!")
}
func Http_Hello() {
beego.Router("/", &HomeController{})
beego.Run()
}
编译运行
go build -o hello hello.go
./hello
浏览效果
打开浏览器并访问 http://localhost:8080
关闭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服务成功: