golang学习之go web 开发http.HandleFunc、http.ListenAndServe与http.Handler

一、hello world

1、定义处理器函数
2、绑定路由处理器函数
3、启动服务并监听服务端口

package main

import (
	"log"
	"net/http"
)
// 1、定义处理器函数
func helloHandler(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("hello world"))
}

func main() {
	// 2、绑定 路由"/hello"和处理器函数helloHandler
	http.HandleFunc("/hello", helloHandler)
	// 3、启动服务并监听8090端口
	err := http.ListenAndServe("localhost:8090", nil)
	if err != nil {
		log.Fatal(err)
	}
}

二、http.HandleFunc

1、从hello world代码中可以看到HandleFunc的功能是绑定路由处理器函数,跟进HandleFunc源码

func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
	DefaultServeMux.HandleFunc(pattern, handler)
}

2、跟进DefaultServeMux可以看到是ServeMux结构体类型变量

var DefaultServeMux = &defaultServeMux
var defaultServeMux ServeMux

3、跟进ServeMux结构体,可以看到包含一个map[string]muxEntry类型字段m

type ServeMux struct {
	mu    sync.RWMutex
	m     map[string]muxEntry
	es    []muxEntry // slice of entries sorted from longest to shortest.
	hosts bool       // whether any patterns contain hostnames
}

4、跟进DefaultServeMux.HandleFunc,DefaultServeMux.HandleFunc内部调用mux.Handle

func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
	if handler == nil {
		panic("http: nil handler")
	}
	mux.Handle(pattern, HandlerFunc(handler))
}

5、跟进mux.Handle(已略去部分代码)

func (mux *ServeMux) Handle(pattern string, handler Handler) {
	// 封装路由器及处理器函数
	e := muxEntry{h: handler, pattern: pattern}
	// 绑定路由与对应处理器函数
	mux.m[pattern] = e
}

综上可以看到http.HandleFunc的功能是绑定路由及处理器函数并注册到DefaultServeMux的map内。

三、http.ListenAndServe

1、跟进源码,看到内部调用server.ListenAndServe()

func ListenAndServe(addr string, handler Handler) error {
	server := &Server{Addr: addr, Handler: handler}
	return server.ListenAndServe()
}

2、跟进server.ListenAndServe()(已略去部分代码)

func (srv *Server) ListenAndServe() error {
	return srv.Serve(ln)
}

3、跟进srv.Serve(ln) (已略去部分代码)最后一行看到,启动了一个协程 调用 c.serve(connCtx)

func (srv *Server) Serve(l net.Listener) error {
	go c.serve(connCtx)
}

4、跟进c.serve(connCtx)(已略去部分代码)看到一行如下代码

serverHandler{c.server}.ServeHTTP(w, w.req)

5、跟进ServeHTTP(w, w.req)(已略去部分代码),可以看到当handler为nil时使用默认Handler即DefaultServeMux

func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) {
	handler := sh.srv.Handler
	if handler == nil {
		handler = DefaultServeMux
	}
	handler.ServeHTTP(rw, req)
}

6、跟进DefaultServeMux.ServeHTTP(rw, req)(已略去部分代码)

func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) {
	// 查询已注册的处理器函数
	h, _ := mux.Handler(r)
	// 调用注册的处理器函数
	h.ServeHTTP(w, r)
}

7、跟进mux.Handler( r )到最后一行代码(已略去部分代码)

func (mux *ServeMux) Handler(r *Request) (h Handler, pattern string) {
	return mux.handler(host, r.URL.Path)
}

8、跟进mux.handler(host, r.URL.Path),看到当找不到对应处理器函数时返回NotFoundHandler 404页面处理器函数

func (mux *ServeMux) handler(host, path string) (h Handler, pattern string) {
	mux.mu.RLock()
	defer mux.mu.RUnlock()

	// Host-specific pattern takes precedence over generic ones
	if mux.hosts {
		h, pattern = mux.match(host + path)
	}
	if h == nil {
		h, pattern = mux.match(path)
	}
	if h == nil {
		h, pattern = NotFoundHandler(), ""
	}
	return
}

9、跟进mux.match(path),可以看到处理器函数就是http.HandleFunc注册到map中的

func (mux *ServeMux) match(path string) (h Handler, pattern string) {
	v, ok := mux.m[path]
	if ok {
		return v.h, v.pattern
	}
}

四、http.Handler

hello world 中http.ListenAndServe(“localhost:8090”, nil)出入的http.Handler是nil,当handler为nil时使用默认的handler。现在传入一个自定义http.Handler

package main

import (
	"log"
	"net/http"
)

type myHandler struct {
}

func (myHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	switch r.URL.Path {
	case "/hello":
		helloHandler(w, r)
	default:
		http.NotFound(w, r)
	}
}

func helloHandler(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("hello world"))
}

func main() {
	var handler myHandler
	err := http.ListenAndServe("localhost:8090", handler)
	if err != nil {
		log.Fatal(err)
	}
}

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
引用中提到了http.Handler的ServeHTTP方法。在这个方法中,首先检查handler是否为空,如果为空,则使用默认的处理程序DefaultServeMux来处理请求。这意味着http.Handler是一个接口类型,它定义了ServeHTTP方法,并且可以根据需要被替换为不同的处理程序。在引用的示例代码中,自定义的myHandler类型实现了http.Handler接口,并定义了ServeHTTP方法来处理不同的URL路径。在main函数中,将自定义的myHandler作为参数传递给http.ListenAndServe函数来处理HTTP请求。这样,当有请求到达时,会根据URL路径来选择相应的处理程序。这种方式使得web服务器能够将请求分派给任意的http.Handler,而不需要考虑其具体类型。这也体现了在Go语言中,满足同一个接口的不同类型是可以替换的。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [golang学习之go web 开发http.HandleFunchttp.ListenAndServehttp.Handler](https://blog.csdn.net/weixin_56349119/article/details/126335261)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *3* [Go语言圣经 - 第7章 接口 - 7.7 http.Handler 接口](https://blog.csdn.net/weixin_51487151/article/details/122318673)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值