首先通过一个函数启动一个服务器,只提供一个方法并返回Hello World!,当你在浏览器输入http://127.0.0.1:8080,就会看到Hello World

对于http.ListenAndServe来说,需要我们提供一个Addr和一个Handler,所以当我们使用Hello实现了HandlerServeHTTP方法后,Hello就会被认为是一个Handler,并将其提供给http.ListenAndServe后会自动调用ServeHTTP方法。

type Hello struct {
} func (hello Hello) ServeHTTP(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello World!"))
} func main() {
http.ListenAndServe(":8080", Hello{})
}

根据上图我们看到httpListenAndServe调用了Server中的ListenAndServe方法,所以以上代码可以写成,再次使用浏览器访问http://127.0.0.1:8080,我们看到了Hello World

type Hello struct {
} func (hello Hello) ServeHTTP(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello World!"))
} func main() {
server := http.Server{Addr: ":8080", Handler: Hello{}}
server.ListenAndServe()
}

以上的方法我们只能通过根路径访问我们想要的结果,如何使用不同的路径访问不同的处理程序呢,你可以写成下面这样,使用http的Handle方法,把路径和程序关联起来并注册到程序中。使用浏览器访问http://127.0.0.1:8080/hello,我们看到了Hello World,那如果访问http://127.0.0.1:8080会是什么呢,我们看一下,是404 page not found

type Hello struct {
} func (hello Hello) ServeHTTP(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello World!"))
} func main() {
http.Handle("/hello", Hello{})
http.ListenAndServe(":8080", nil)
}

好的,我们继续看httpHandle做了什么,点开源码,发现它使用DefaultServeMux调用了一个Handle函数

func Handle(pattern string, handler Handler) { DefaultServeMux.Handle(pattern, handler) }

DefaultServeMux是什么,我们继续展开,发现DefaultServeMuxServeMux实例的一个指针,而且ServeMux是一个struct,通过Handle方法把程序路径和程序进行注册。

// DefaultServeMux is the default ServeMux used by Serve.
var DefaultServeMux = &defaultServeMux var defaultServeMux ServeMux // Handle registers the handler for the given pattern.
// If a handler already exists for pattern, Handle panics.
func (mux *ServeMux) Handle(pattern string, handler Handler) {
mux.mu.Lock()
defer mux.mu.Unlock() if pattern == "" {
panic("http: invalid pattern")
}
if handler == nil {
panic("http: nil handler")
}
if _, exist := mux.m[pattern]; exist {
panic("http: multiple registrations for " + pattern)
} if mux.m == nil {
mux.m = make(map[string]muxEntry)
}
e := muxEntry{h: handler, pattern: pattern}
mux.m[pattern] = e
if pattern[len(pattern)-1] == '/' {
mux.es = appendSorted(mux.es, e)
} if pattern[0] != '/' {
mux.hosts = true
}
}

继续观察这个struct,发现它实现了ServeHTTP,那也就是说明ServeMux是一个Handler

// ServeHTTP dispatches the request to the handler whose
// pattern most closely matches the request URL.
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)
h.ServeHTTP(w, r)
}

根据以上分析发现DefaultServeMux是一个默认的路由程序,它将接收到的不同的程序映射到不同的路径上等待访问,同时它也是一个Handler

现在我把程序变动一下,这样也能达到同样的效果, 使用浏览器访问http://127.0.0.1:8080/hello依然能看到Hello World

func main() {
http.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello World!"))
})
http.ListenAndServe(":8080", nil)
}

http中的HandleFunc又是什么呢,我们点进去看一下,发现这个方法需要传入func(ResponseWriter, *Request)类型的函数。并且最终被传入了我们前面提到的ServeMuxHandle中。但是,我们知道只有实现了ServeHTTP方法才是Handler,而ServeMuxHandle需要一个Handler类型的变量,显然这个handler函数并不是一个真正的Handler

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

但是我们看到它被强转成了HandlerFunc类型。那么我们继续查看HandlerFuncHandlerFunc实现了ServeHTTP,那么这就说明HandlerFunc是一个Handler,所以最终传入到ServeMux.Handle中的HandlerFunc(handler)是一个Handler

// The HandlerFunc type is an adapter to allow the use of
// ordinary functions as HTTP handlers. If f is a function
// with the appropriate signature, HandlerFunc(f) is a
// Handler that calls f.
type HandlerFunc func(ResponseWriter, *Request) // ServeHTTP calls f(w, r).
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
f(w, r)
}

那么我们的代码也可以写成这样:

func Hello(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello World!"))
} func main() {
http.HandleFunc("/hello", Hello)
http.ListenAndServe(":8080", nil)
}

或者这样:

func Hello(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello World!"))
} func main() {
http.Handle("/hello",http.HandlerFunc(Hello))
http.ListenAndServe(":8080", nil)
}

最后http包中还有几个内置的Handler,您可以自己去探索:

NotFoundHandler
StripPrefix
RedirectHandler
TimeoutHandler
FileServer

Handle详解的更多相关文章

  1. android handle详解3 ThreadHandler

    在android handle详解2的基础上,我们来学习ThreadHandler ThreadHandler的本质就是对android handle详解2的实现 HandlerThread其实还是一 ...

  2. android handle详解2 主线程给子线程发送消息

    按照android handler详解分析的原理我们可以知道,在主线程中创建handle对象的时候,主线程默认创建了一个loop对象使用threalocal函数将loop对象和主线程绑定. 我们能不能 ...

  3. android handle详解

    我们来看一个简单的代码: package com.mly.panhouye.handlerdemo; import android.content.Intent; import android.os. ...

  4. Android中Handle详解

    上图为本人总结的Handler,网上发现一片总结很好的博客就copy过来:作为参考 Handler有何作用?如何使用? 一 .Handler作用和概念 包含线程队列和消息队列,实现异步的消息处理机制, ...

  5. Node.js npm 详解

    一.npm简介 安装npm请阅读我之前的文章Hello Node中npm安装那一部分,不过只介绍了linux平台,如果是其它平台,有前辈写了更加详细的介绍. npm的全称:Node Package M ...

  6. JavaScript事件详解-jQuery的事件实现(三)

    正文 本文所涉及到的jQuery版本是3.1.1,可以在压缩包中找到event模块.该篇算是阅读笔记,jQuery代码太长.... Dean Edward的addEvent.js 相对于zepto的e ...

  7. JavaScript事件详解-Zepto的事件实现(二)【新增fastclick阅读笔记】

    正文 作者打字速度实在不咋地,源码部分就用图片代替了,都是截图,本文讲解的Zepto版本是1.2.0,在该版本中的event模块与1.1.6基本一致.此文的fastclick理解上在看过博客园各个大神 ...

  8. @RequestMapping 用法详解之地址映射

    @RequestMapping 用法详解之地址映射 引言: 前段时间项目中用到了RESTful模式来开发程序,但是当用POST.PUT模式提交数据时,发现服务器端接受不到提交的数据(服务器端参数绑定没 ...

  9. 详解Javascript的继承实现(二)

    上文<详解Javascript的继承实现>介绍了一个通用的继承库,基于该库,可以快速构建带继承关系和静态成员的javascript类,好使用也好理解,额外的好处是,如果所有类都用这种库来构 ...

随机推荐

  1. HOOK实现游戏无敌-直接修改客户端-2-使用VS来处理

    HOOK实现游戏无敌-直接修改客户端-2-使用VS来处理 大概流程 1 首先找到游戏进程,打开进程 2 申请一段内存空间来保存我们的硬编码(virtualAllocEx) 3 找到攻击函数,修改函数的 ...

  2. (原创)在Linux上安装运行Python3(CentOS7为例)

    在win10上开发好的python项目要部署在Linux上要面对的问题:怎么在Linux上跑py文件呢? 以Lunix CentOS7.x平台为例,CentOS系统上自带的已有python2.x 的版 ...

  3. Android Studio 之 编写精美的聊天界面

    •准备工作 首先制作一张 .9 格式的聊天气泡,参见我的这篇博客: 需要注意的是,制作完成后,应该将原始文件删除,否则AS会分不清楚而报错. 新建一个 Empty Activity,Java 和 XM ...

  4. Istio 网络弹性 实践 之 故障注入 和 调用重试

    网络弹性介绍 网络弹性也称为运维弹性,是指网络在遇到灾难事件时快速恢复和继续运行的能力.灾难事件的范畴很广泛,比如长时间停电.网络设备故障.恶意入侵等. 重试(attempts) Istio 重试机制 ...

  5. oo第四单元作业总结暨课程总结

    oo第四单元作业总结暨课程总结 一.本单元作业架构设计 本单元需要构建一个UML解析器,通过对输入的UML类图/顺序图/状态图的相关信息进行解析以供查询,其中课程组已提供输入整体架构及输入解析部分,仅 ...

  6. springboot项目整合mybatis

    记录创建springboot项目并配置mybatis中间件: 资源准备及版本说明 编程工具:IDEA JDK版本:1.8 Maven版本:Apache Maven 3.6.3 springboot版本 ...

  7. Java多线程详解——一篇文章搞懂Java多线程

    目录 1. 基本概念 2. 线程的创建和启动 2.1. 多线程实现的原理 2.2.多线程的创建,方式一:继承于Thread类 2.3.多线程的创建,方式一:创建Thread匿名子类(也属于方法一) 2 ...

  8. 内网渗透-windows认证

    前言:全国HW刚结束,加强一波内网概念,去年11月红队成绩并不理想,这次必拿下好成绩.冲!!! 0x00 本地认证 本地认证基础知识 在本地登录Windows的情况下,操作系统会使用用户输入的密码作为 ...

  9. k8s daemonset

    DaemonSet控制器会在每个节点上运行单一的副本,他非常适合部署那些节点本身提供服务或者执行维护的 Pod 例如 : 存储相关,每个节点上运行glusterd, ceph 日志收集相关,每个节点上 ...

  10. Selenium3自动化测试【16】元素定位之Tag

    @ 目录 1. 通过tag name定位Bing案例 2. 通过tag name定位一组元素案例 3.[测试全系列视频课程]请点击我哦..... tag name方法是通过对HTML页面中tag na ...