Handle详解
首先通过一个函数启动一个服务器,只提供一个方法并返回Hello World!
,当你在浏览器输入http://127.0.0.1:8080
,就会看到Hello World
。
对于http.ListenAndServe
来说,需要我们提供一个Addr
和一个Handler
,所以当我们使用Hello
实现了Handler
的ServeHTTP
方法后,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{})
}
根据上图我们看到http
的ListenAndServe
调用了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)
}
好的,我们继续看http
的Handle
做了什么,点开源码,发现它使用DefaultServeMux
调用了一个Handle
函数
func Handle(pattern string, handler Handler) { DefaultServeMux.Handle(pattern, handler) }
那DefaultServeMux
是什么,我们继续展开,发现DefaultServeMux
是ServeMux
实例的一个指针,而且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)
类型的函数。并且最终被传入了我们前面提到的ServeMux
的Handle
中。但是,我们知道只有实现了ServeHTTP
方法才是Handler
,而ServeMux
的Handle
需要一个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
类型。那么我们继续查看HandlerFunc
,HandlerFunc
实现了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详解的更多相关文章
- android handle详解3 ThreadHandler
在android handle详解2的基础上,我们来学习ThreadHandler ThreadHandler的本质就是对android handle详解2的实现 HandlerThread其实还是一 ...
- android handle详解2 主线程给子线程发送消息
按照android handler详解分析的原理我们可以知道,在主线程中创建handle对象的时候,主线程默认创建了一个loop对象使用threalocal函数将loop对象和主线程绑定. 我们能不能 ...
- android handle详解
我们来看一个简单的代码: package com.mly.panhouye.handlerdemo; import android.content.Intent; import android.os. ...
- Android中Handle详解
上图为本人总结的Handler,网上发现一片总结很好的博客就copy过来:作为参考 Handler有何作用?如何使用? 一 .Handler作用和概念 包含线程队列和消息队列,实现异步的消息处理机制, ...
- Node.js npm 详解
一.npm简介 安装npm请阅读我之前的文章Hello Node中npm安装那一部分,不过只介绍了linux平台,如果是其它平台,有前辈写了更加详细的介绍. npm的全称:Node Package M ...
- JavaScript事件详解-jQuery的事件实现(三)
正文 本文所涉及到的jQuery版本是3.1.1,可以在压缩包中找到event模块.该篇算是阅读笔记,jQuery代码太长.... Dean Edward的addEvent.js 相对于zepto的e ...
- JavaScript事件详解-Zepto的事件实现(二)【新增fastclick阅读笔记】
正文 作者打字速度实在不咋地,源码部分就用图片代替了,都是截图,本文讲解的Zepto版本是1.2.0,在该版本中的event模块与1.1.6基本一致.此文的fastclick理解上在看过博客园各个大神 ...
- @RequestMapping 用法详解之地址映射
@RequestMapping 用法详解之地址映射 引言: 前段时间项目中用到了RESTful模式来开发程序,但是当用POST.PUT模式提交数据时,发现服务器端接受不到提交的数据(服务器端参数绑定没 ...
- 详解Javascript的继承实现(二)
上文<详解Javascript的继承实现>介绍了一个通用的继承库,基于该库,可以快速构建带继承关系和静态成员的javascript类,好使用也好理解,额外的好处是,如果所有类都用这种库来构 ...
随机推荐
- ElasticSearch实战系列十: ElasticSearch冷热分离架构
前言 本文主要介绍ElasticSearch冷热分离架构以及实现. 冷热分离架构介绍 冷热分离是目前ES非常火的一个架构,它充分的利用的集群机器的优劣来实现资源的调度分配.ES集群的索引写入及查询速度 ...
- Netflix业务运维分析和总结
目录 Netflix工作环境的分析和思考 为什么Netflix会做得如此极致? 海量业务规模下的技术架构和挑战 更加合理的组织架构和先进的工具体系及理念 自由与责任并存的企业文化 当前问题: 精选提问 ...
- flexbox(弹性盒布局模型),以及适用场景
一.是什么 Flexible Box 简称 flex,意为"弹性布局",可以简便.完整.响应式地实现各种页面布局 采用Flex布局的元素,称为flex容器container 它的所 ...
- C#中SQLite的使用及工具类
目录 SQLite简介 存储类 亲和类型 引用System.Data.SQLite.dll 软件包分类 使用本机库预加载 常用部署包 工具类 参考资料 SQLite简介 SQLite是一款轻型的数据库 ...
- ThoughtWorks首席咨询师带你一站通关中台
大家都在谈中台,是当下一个热议的话题,但是我们最关心的两个基本问题还是没有答案.一个是中台的概念,依然是见仁见智,始终没有一个统一的见解:另一个是中台的落地,更是鲜有人谈. 拨开当下有关中台的层层迷雾 ...
- 跨域库herryPostMessage.js的一些优化,多iframe跨域
旧库见文章:https://www.cnblogs.com/wuhairui/p/14595893.html 新版库主要做了下多个iframe和父页面交互的优化.主要使用构造函数的方式将多个ifram ...
- 统计学习方法——实现AdaBoost
Adaboost 适用问题:二分类问题 模型:加法模型 \[f(x)=\sum_{m=1}^{M} \alpha_{m} G_{m}(x) \] 策略:损失函数为指数函数 \[L(y,f(x))=ex ...
- Day16_89_通过反射机制获取所有构造方法
通过反射机制获取某个特定的构造方法 * 代码 import java.lang.reflect.Constructor; import java.lang.reflect.Modifier; publ ...
- tidb初体验
安装 docker-compose: https://github.com/pingcap/tidb-docker-compose pd tikv tidb各单个节点,单个副本,限制内存,cpu等,防 ...
- 利用主机域名配置Apache的虚拟主机功能
利用主机域名配置Apache的虚拟主机功能,可以减轻服务器为每一个网站分配IP地址的压力.而且根据不同的主机域名可以输出不同的网页内容.要实现此项功能,可以通过修改/etc/host文件来强制定义IP ...