14_Http编程

发布时间 2023-10-08 13:19:46作者: Stitches

2、性能更高的第三方库 HttpRouter

https://github.com/julienschmidt/httprouter

https://pkg.go.dev/github.com/julienschmidt/httprouter

2.1 HttpRouter 与 net/http 比较

  • HttpRouter 相较于 Go语言官方库 net/http 性能更高,它支持URL中携带访问参数、支持多种访问类型(GET、POST、PUT、DELETE)。性能对比参考: https://github.com/julienschmidt/go-http-routing-benchmark

  • 精确的路径匹配。对比net/http 中的 ServeMux,ServeMux 请求的URL路径可以匹配多个模式,它有多种模式优先级规则,如最长前缀匹配、首次匹配。而 HttpRouter 对于每种URL请求路径,一个请求只能完全匹配一个或没有路由。

  • net/http 底层采用 map来存储 pattern 和 handler。而 HttpRouter 采用带有优先级节点的树状结构进行存储,对于每一种请求方式,它都维护了一棵单独的优先级树,相较于 net\http 的map存储结构而言,占用空间更小,并且在查找URL对应的Handler时速度更快。

    image-20221015140825432

2.2 嵌入中间件

2.2.1 服务于多个领域主机

​ 当前服务器有多个领域主机,实现多个领域主机都能访问到web资源。

type HostSwitch map[string]http.Handler   //定义多个主机地址到Handler的映射

func Index(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	fmt.Fprintln(w, "hello gopher!")
}

func Hello(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	fmt.Fprintf(w, "hello, %s!\n", ps.ByName("name"))
}

func (hs HostSwitch) ServeHTTP(w http.ResponseWriter, r *http.Request) {  //重定义ServeHTTP方法
	if handler := hs[r.Host]; handler != nil {
		handler.ServeHTTP(w, r)
	} else {
		http.Error(w, "Forbidden", 403)
	}
}

func TestHttpRouterMiddlewares(t *testing.T) {
	router := httprouter.New()
	router.GET("/", Index)
	router.GET("/hello/:name", Hello)
	//注册多host
	hs := make(HostSwitch)
	hs["example.com:12345"] = router
	hs["localhost:12345"] = router
	log.Fatal(http.ListenAndServe(":12345", hs))
}

2.2.2 基础身份验证

//闭包实现身份验证,验证参考 Basic Authentication (RFC 2617) for handles
func BasicAuth(h httprouter.Handle, requiredUser, requiredPass string) httprouter.Handle {
	return func(writer http.ResponseWriter, request *http.Request, params httprouter.Params) {
		user, password, hasAuth := request.BasicAuth()
		if hasAuth && user == requiredUser && password == requiredPass {
			h(writer, request, params)
		} else {
			writer.Header().Set("WWW-Authenticate", "Basic realm=Restricted")
			http.Error(writer, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
		}
	}
}

func Protected(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	fmt.Fprint(w, "Protected!\n")
}

func TestHttpRouterMiddlewares2(t *testing.T) {
	user := "user"
	password := "123456"
	router := httprouter.New()
	router.GET("/", Index)
	router.GET("/protected/", BasicAuth(Protected, user, password))
	log.Fatal(http.ListenAndServe(":8080", router))
}