博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Golang web之http标准库简析
阅读量:6984 次
发布时间:2019-06-27

本文共 3912 字,大约阅读时间需要 13 分钟。

本文首先介绍使用http标准库搭建web服务,共三种方式,然后简析内部实现原理,最后对http的使用做出总结。阅读本文需要简单的go基础知识和web开发相关知识。

1.使用http搭建简单的web服务

1.1 单个handler形式

func main() {	server := http.Server{    	Addr:    "127.0.0.1:8081",    	Handler: &helloHandler{},	}	_ = server.ListenAndServe()}type helloHandler struct{}func (h *helloHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {	_, _ = fmt.Fprintf(w, "hello World")}复制代码
  • 监听8081端口。
  • 只有一个Handler的实现,所有的请求都由helloHandlerServeHTTP方法处理。访问localhost:8081localhost:8081/alocalhost:8081/a/a都返回hello World
  • 显然此方式很简陋无法满足需求。

1.2 多个handler

func main() {	server2 := http.Server{    	Addr: "127.0.0.1:8082",	}	http.Handle("/hello", &helloHandler{})	http.Handle("/hi", &hiHandler{})	_ = server2.ListenAndServe()}type helloHandler struct{}func (h *helloHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {	_, _ = fmt.Fprintf(w, "hello World")}type hiHandler struct{}func (h *hiHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {	_, _ = fmt.Fprintf(w, "hi World")}复制代码
  • 监听8082端口。
  • 注册了/hello/hi两个路由,helloHandlerhiHandlerServeHTTP方法分别处理。
  • 方式一相比较,没有为Server指定Handler属性。而http库为我们默认指定了一个名称为DefaultServeMux(server.go:2196)的Handler。 可以自己指定Handler,如下。
mux := http.NewServeMux()	mux.Handle("/hello", &helloHandler{})	mux.Handle("/hi", &hiHandler{})		server2 := http.Server{    	Addr: "127.0.0.1:8082",    	Handler:mux,	}复制代码

1.3 HandlerFunc

func main() {	server3 := http.Server{    	Addr: "127.0.0.1:8083",	}	http.HandleFunc("/hello", helloFunc)	http.HandleFunc("/hi", hiFunc)	_ = server3.ListenAndServe()}func helloFunc(w http.ResponseWriter, r *http.Request)  {	_, _ = fmt.Fprintf(w, "hello World")}func hiFunc(w http.ResponseWriter, r *http.Request)  {	_, _ = fmt.Fprintf(w, "hi World")}复制代码
  • 监听8083端口。
  • 注册了/hello/hi两个路由,分别由helloFunchiFunc两个函数处理。
  • 同方式二一样,并没有为Server指定Handler属性,由标准库自己指定。可以自己指定Handler,如下。
mux := http.NewServeMux()mux.HandleFunc("/hello",helloFunc)mux.HandleFunc("/hi",hiFunc)	server3 := http.Server{    Addr: "127.0.0.1:8083",	Handler:mux,}复制代码

2.http库内部实现简析

2.1 http.Server

http.Server源码:

type Server struct {	Handler Handler // handler to invoke, http.DefaultServeMux if nil	...	...}复制代码

http.Handler源码:

type Handler interface {	ServeHTTP(ResponseWriter, *Request)}复制代码
  • Server结构中Handler接口是真正处理所有请求的。
  • 传入自定义的Handler必须实现Handler重写ServeHTTP方法,例如方式一。
  • 当没有指定Handler时,http标准库有一个默认的实现http.DefaultServeMux
  • ServeMux结构体的ServeHTTP负责将请求映射到我们注册的handler,不是直接在方法中处请求。逻辑如下:
func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) {	if r.RequestURI == "*" {    	if r.ProtoAtLeast(1, 1) {    	    w.Header().Set("Connection", "close")    	}    	w.WriteHeader(StatusBadRequest)    	return	}	h, _ := mux.Handler(r) //根据请求寻找对应的Handler	h.ServeHTTP(w, r) //调用我们自己的handler,处理请求}复制代码
  • ServeMux主要有两个功能。其一,实现路由注册,方法是func (mux *ServeMux) Handle(pattern string, handler Handler)func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)),路由信息存储在map中。其二实现请求路由,方法是func (mux * ServeMux) ServeHTTP(w ResponseWriter, r *Request)

http.ServeMux源码

type ServeMux struct {	m     map[string]muxEntry //存储路由信息	...}复制代码

2.2HandlerHandlerFunc比较

  • 路由注册时调用方法不同。自定义的HandlerHandlerFunc分别调用http.Handlehttp.HandleFunc。例如:http.Handle("/hello", &helloHandler{})http.HandleFunc("/hello", hiFunc)
  • 实现http.Handler接口的方式不同。自定义的Handler定义一个签名为ServeHTTP(w ResponseWriter, r *Request)的方法就行。而自定义HandlerFunc不仅方法参数与ServeHTTP一样,并且在内部实现了转换。
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {    ...	mux.Handle(pattern, HandlerFunc(handler))//调用HandlerFunc实现类型转换}复制代码

HandlerFunc类型

type HandlerFunc func(ResponseWriter, *Request)//实现了`http.Handler`func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {	f(w, r)}复制代码

3.总结

  • 面向接口编程,标准库定义接口Handler,并且有自己的内部实现ServeMux,使用者这也可以自己实现,例如,使用过Spring的同学应该深有体会。接口作为一种规范,既有约束性,又有扩展性。

  • 函数式编程,在golang中,函数可以不仅可以作为参数、返回值,还可以作为一种类型,例如HandlerFunc。函数类型可以自己有的方法,实现接口,并且将具有相同参数的函数转化为特定类型,例如HandlerFunc(handler),将普通函数handler转化为HandlerFunc类型。

下一节介绍

转载地址:http://ilxpl.baihongyu.com/

你可能感兴趣的文章
vue.js+vscode+visual studio在windows下搭建开发环境
查看>>
puppet 基础篇
查看>>
Java开发GUI之Dialog弹出窗口
查看>>
云架构的基础转变会带来哪些变化?
查看>>
如何将视频下载并且转码拼接
查看>>
Alcatraz插件安装问题
查看>>
轻松了解“Web应用防火墙”
查看>>
Kubernetes基础文档(链接,下载,安装,架构)
查看>>
PEEK材料再获突破,对3D打印产业影响几何
查看>>
无线加速度传感器
查看>>
设计模式
查看>>
Zend Studio 0x80070666错误解决
查看>>
Mac应用程序无法打开或文件损坏的处理方法
查看>>
网址被微信拦截怎么办 微信屏蔽的域名如何正常访问
查看>>
@ModelAttribute运用详解
查看>>
思科交换机VTP配置
查看>>
正则表达式
查看>>
Mysql中使用命令行导入.sql文件新建数据库表(图文)
查看>>
RUBY有感
查看>>
spring 配置多数据源
查看>>