GoWeb搭建简单服务器

  1. 多路复用器ServeMux和DefaultServeMux

    当一个Http请求发送到服务端后,首先要做的就是多路复用器进行请求转发到相应的处理器。在Go中内置了ServeMux这个结构体,它会将每一个接收的请求的URL与一个注册模式的列表进行匹配,并调用和URL最匹配的模式的处理器。而DefaultServeMux是net/http包中默认提供的一个多路复用器,本质是ServeMux的一个实例。

  2. HandleFunc()函数

    func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) 函数的含义如下:HandleFunc注册一个处理器函数handler和对应的模式pattern。具体代码如下:

func main() {
	http.HandleFunc("/hello", hello)//传入hello这个函数作为处理器函数
	http.ListenAndServe(":8080",nil)
}

func hello(writer http.ResponseWriter, request *http.Request) {
	fmt.Fprint(writer, "通过HandleFunc()函数进行请求处理!")
}

传入的处理器函数,在方法内部会通过DefaultServeMux.HandleFunc(pattern, handler) 封装成处理器,具体源码如下:

func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
	DefaultServeMux.HandleFunc(pattern, handler)
}
------------------------------------------------------------------------------------
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
	if handler == nil {
		panic("http: nil handler")
	}
	mux.Handle(pattern, HandlerFunc(handler))
}//可以看到,传入的handler函数在最后一行代码被封装成了处理器
  1. Handle()函数

    通过handle()函数,可以来指定处理器func (mux *ServeMux) Handle(pattern string, handler Handler) Handle注册HTTP处理器handler和对应的模式pattern。如果该模式已经注册有一个处理器,Handle会panic。具体代码如下:
type MyHandler struct{}

func (m *MyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "通过自己创建的处理器处理请求!",r.URL.Path )
}

func main() {
	 myHandler := MyHandler{}
	http.Handle("/hello", &myHandler)
	http.ListenAndServe(":8080", nil)//创建路由
}

Go内置了handle结构,并且结构内部只有serveHttp()一个方法,而这个serveHttp()方法是GoWeb中十分重要的一个函数,能根据URL查找对应的处理器,移交请求,具体结构源码:

type Handler interface {
    ServeHTTP(ResponseWriter, *Request)
}

所以我们自定义的处理器只要实现ServeHTTP()方法,就是实现了Handler接口。而在Handle()方法中,由于我们没有自定义多路复用器,会调用内置的默认多路复用器也就是DefaultServeMux进行处理,其他内容可参考 2 的源码部分。

  1. 自定义Server服务器结构

    上面2中方法我们能发现,在http.ListenAndServe(":8080", nil) 这行代码中,总是在第二个参数传入一个nil,深入查看可以发现,在这个方法内部是这样的:
源码:
func ListenAndServe(addr string, handler Handler) error {
	server := &Server{Addr: addr, Handler: handler}
	return server.ListenAndServe()
}

可以看到Go在内部自定义了一个Server结构体,并且最终还是通过调用这个结构体的无参ListenAndServe()方法进行操作,这个结构全部内容如下:

type Server struct {
    Addr           string        // 监听的TCP地址,如果为空字符串会使用":http"
    Handler        Handler       // 调用的处理器,如为nil会调用http.DefaultServeMux
    ReadTimeout    time.Duration // 请求的读取操作在超时前的最大持续时间
    WriteTimeout   time.Duration // 回复的写入操作在超时前的最大持续时间
    MaxHeaderBytes int           // 请求的头域最大长度,如为0则用DefaultMaxHeaderBytes
    TLSConfig      *tls.Config   // 可选的TLS配置,用于ListenAndServeTLS方法
    // TLSNextProto(可选地)指定一个函数来在一个NPN型协议升级出现时接管TLS连接的所有权。
    // 映射的键为商谈的协议名;映射的值为函数,该函数的Handler参数应处理HTTP请求,
    // 并且初始化Handler.ServeHTTP的*Request参数的TLS和RemoteAddr字段(如果未设置)。
    // 连接在函数返回时会自动关闭。
    TLSNextProto map[string]func(*Server, *tls.Conn, Handler)
    // ConnState字段指定一个可选的回调函数,该函数会在一个与客户端的连接改变状态时被调用。
    // 参见ConnState类型和相关常数获取细节。
    ConnState func(net.Conn, ConnState)
    // ErrorLog指定一个可选的日志记录器,用于记录接收连接时的错误和处理器不正常的行为。
    // 如果本字段为nil,日志会通过log包的标准日志记录器写入os.Stderr。
    ErrorLog *log.Logger
    // 内含隐藏或非导出字段
}

那么我们是不是也可以创建一个Server的 实例,直接调用无参ListenAndServe()函数呢?

type MyHandler struct{}

func (m *MyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "通过自己创建的多路复用器处理请求!",r.URL.Path )
}

func main() {
	myHandler := MyHandler{}
	//创建Server结构,配置详细信息
	server := http.Server{
		Addr: ":8080",
		Handler: &myHandler,
		ReadTimeout: 2 * time.Second,
	}
	 server.ListenAndServe()
}
  1. 自定义多路复用器

    上述几种搭建服务器方法中,我们都用的是内置的默认多路复用器,从上面的源码中可以看到其实也可以自己定义一个多路复用器实例,直接调用多路复用器实例的mux.HandleFunc() 方法即可。
func main() {
	mux := http.NewServeMux()//创建一个多路复用器
	mux.HandleFunc("/hello", handle)
	http.ListenAndServe(":8080", mux)
}

func hello(writer http.ResponseWriter, request *http.Request) {
	fmt.Fprint(writer, "通过HandleFunc()函数进行请求处理!")
}

  1. HttpRouter

serveMux的缺陷是无法使用实现URL模式匹配,可以由第三方HttpRouter包实现这个功能,具体在github上可以超找到相关路由包。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值