// 示例
// net/http
package http
type Handler interface{
ServeHTTP(w ResponseWriter, r *Request)
}
func ListenAndServe(address string, h Handler) error ListenAndServe函数需要一个例如"localhost:8000"的服务器地址,和一个所有请求都可以分派的Handler接口实例。它会一直运行,直到这个服务因为一个错误而失败(或者启动失败),它的返回值一定是一个非空的错误。 // 例子
想象一个电子商务网站,为了销售,将数据库中物品的价格隐射成美元。下面这个程序可能是能想到的最简单的实现了。它将库存清单模型化为一个命名为database的map类型,我们给这个类型一个ServeHTTP方法,这样它可以满足http.Handler接口。这个handler会遍历整个map并输出物品信息
func main(){
db := database{"shoes": 50, "socks": 5}
log.Fatal(http.ListenAndServe("localhost:8000", db))
}
type dollars float32 func (d dollars) String() string {return fmt.Sprintf("$%.2f", d)} type database map[string]dollars
// 实现Handler接口中定义的ServeHTTP方法
func (db database) ServeHTTP(w http.ResponseWriter, req *http.Request){
for item, price := range db{
fmt.Fprintf(w, "%s: %s\n", item, price)
}
} // 带有查询字符串的请求
// /price?item=socks
func (db datbase) ServeHTTP(w http.ResponseWriter, rep *http.Request){
switch req.URL.Path{
case "/list":
for item, price := range db{
fmt.Fprintf(w, "%s: %s\n", item, price)
}
case "/price":
item := req.URL.Query().Get("item")
price, ok := db[item]
if !ok{
w.WriteHeader(http.StatusNotFound)
fmt.Fprintf(w, "no such item:%q\n", item)
return
}
fmt.Fprintf(w, "%s\n", price)
default:
w.WriteHeader(http.StatusNotFound)
fmt.Fprintf(w, "no such page: %s\n", req.URL)
}
}
现在handler基于URL的路径部分(req.URL.Path)来决定执行什么逻辑。如果这个handler不能识别这个路径,它会通过调用w.WriteHeader(http.StatusNotFound)返回客户端一个HTTP错误;这个检查应该在向w写入任何值前完成。(顺便提一下, http.ResponseWriter是另一个接口,它在io.Writer上增加了发生HTTP相应头的方法)。等效的我们可以使用http.Error函数:
msg := fmt.Sprintf("no such page: %s\n", req.URL)
http.Error(w, msg, http.StatusNotFound) /price的case会调用URL的Query方法来将HTTP请求参数解析为一个map,或者更准确的说一个net/url包中url.Values类型的多重因隐射。然后找到第一个item参数并查找它的价格。没有找到会返回一个错误。 // 使用请求多路器ServeMux来简化URL和handers
func main(){
db := database{"shoes": 50, "socks": 5}
mux := http.NewServeMux()
mux.Handle("/list", http.HandlerFunc(db.list))
mux.Handle("/price", http.HandleFunc(db.Price))
log.Fatal(http.ListenAndServe("localhost:8000", mux)) // 将mux作为handler
}
type database map[string]dollars func (db database) list(w http.ResponseWriter, req *http.Request){
for item, price := range db{
fmt.Fprintf(w, "%s:%s\n", item, price)
}
} func (db database) price(w http.ResponseWriter, req *http.Request){
item := req.Query().Get("item")
price,ok := db[item]
if !ok{
w.WriteHeader(http.StatusNotFound)
fmt.Fprintf(w, "no such item: %q\n", item)
return
}
fmt.Fprintf(w, "%s\n", price)
} 让我们关注这两个注册到handlers上的调用。第一个db.list是一个方法值,它是下面这个类型的值。
func (w http.ResponseWriter, req *http.Request)
也就是说db.list的调用会缓引一个接收者是db的database.list方法。所以db.list是一个实现了handler类似行为的函数,但是因为它没有方法(理解:该方法没有它自己的方法),所以它不满足http.Handler接口并且不能直接传给mux.Handle.
语句http.HandlerFunc(db.list)是一个转换而非一个函数调用,因为http.HandlerFunc是一个类型。它有如下定义:
package http
type HandlerFunc(w ReponseWriter, r *Request)
func (f HandlerFunc)ServeHTTP(w ResponseWriter, r *Request){
f(w, r)
} HandlerFunc显示了go语言接口机制中一些不同寻常的特点,这是一个实现了接口http.Handler的方法的函数。
ServeHTTP方法的行为是调用了它的函数本身。因此HandlerFunc是一个让函数值满足一个接口的适配器,这里函数和这个接口仅有的方法有相同的函数签名。实际上,这个技巧让一个单一的类型,例如database以多种方式满足http.Handler接口:一种通过它的list方法,一种通过它的price方法等。
因为handler通过这种方式注册非常普遍,ServeMux有一个方便的HandlerFunc方法,它帮我们简化handler注册代码成这样:
mux.HandleFunc("/list", db.list)
mux.HandleFunc("/price", db.price) 从上面代码很容易看出应该怎么构建一个程序:由两个不同的web服务器监听不同的端口,并且定义不同的URL将它们指派到不同的handler。我们只要构建另外一个ServeMux并且再调用一次ListenAndServe(可能并行的)。但是在大多数程序中,一个web服务器就足够了。此外,在一个应用程序的多个文件中定义HTTP handler也是非常典型的,如果他们必须全部都显示地注册到这个应用的ServeMux实例上会比较麻烦。
所以为了方便,net/http包提供了一个全局的ServeMux实例DefaultServerMux和包级别的http.Handle和http.HandleFunc函数。现在,为了使用DefaultServeMux作为服务器的主handler,我们不需要将它传给ListenAndServe函数;nil值就可以工作。
func main(){
db := database("shoes": 50, "socks": 5)
http.HandleFunc("/list", db.list)
http.HandleFunc("/price", db.price)
log.Fatal(http.ListenAndServe("localhost:8000", nil))
}

http.Handler接口的更多相关文章

  1. Golang 接口型函数和http.Handler接口

    一.接口型函数 参考Golang必备技巧:接口型函数 1.原始接口实现 type Handler interface { Do(k, v interface{}) } func Each(m map[ ...

  2. JAX-WS使用Handler Chain加工消息

    承前 本文的示例,是基于前一篇文章中的实例而改进的,如果想要运行本文的代码例子,需要先实现前一篇的代码. 前一篇文章JAX-WS开发WebService初级 Handler概念 在WebService ...

  3. http.Handler 与Go的错误处理

    原文地址    在之前我写过一篇关于通过使用http.HandlerFunc来实现一个定制handler类型用来避免一些平常的错误的文章.func MyHandler(w http.ResponseW ...

  4. Go 接口转换的一个例子

    今天将Go 的websocket集成到已有的http中时也遇到以下一个问题:其中主要是接口类型转换 转载自[http://www.cnblogs.com/ghj1976/archive/2013/04 ...

  5. Go Web:Handler

    Multiplexer根据URL将请求路由给指定的Handler.Handler用于处理请求并给予响应.更严格地说,用来读取请求体.并将请求对应的响应字段(respones header)写入Resp ...

  6. Netty核心概念(6)之Handler

    1.前言 本节介绍Netty中第三个重要的概念——Handler,这个在前两节都提到了,尤其是Channel和Handler联系紧密.handler本身的设计非常简单,但是所起到的作用却很大,Nett ...

  7. golang技巧-接口型函数

    接口型函数:指的是用函数实现接口,这样在调用的时候就会非常简便,这种函数为接口型函数,这种方式适用于只有一个函数的接口. 定义一个类型,这个类型只定义了函数的参数列表,函数参数列表与接口定义的方法一致 ...

  8. golang http 服务器的接口梳理

    golang http 服务器的接口梳理 Golang构建HTTP服务(二)--- Handler,ServeMux与中间件 Hanlde和HandleFunc以及Handler, HandlerFu ...

  9. java代码之美(14)---Java8 函数式接口

    Java8 函数式接口 之前写了有关JDK8的Lambda表达式:java代码之美(1)---Java8 Lambda 函数式接口可以理解就是为Lambda服务的,它们组合在一起可以让你的代码看去更加 ...

  10. java代码(14) --Java8函数式接口

    Java8函数式接口 之前有关JDK8的Lambda表达式 Java代码(1)--Java8 Lambda 函数式接口可以理解就是为Lambda服务的,它们组合在一起可以让你的代码看去更加简洁 一.概 ...

随机推荐

  1. [转帖]调试springboot数据库系统应用时常用debug日志配置, 解决问题缩小范围时常用

    https://www.yihaomen.com/article/1853.html 摘要: 用 spring boot 开发应用时,在遇到麻烦问题时,经常会打开debug日志,下面记录一个通用的思路 ...

  2. [转帖]HTTP 框架 Hertz 实践入门:性能测试指南

    https://maimai.cn/article/detail?fid=1767401397&efid=R2_kM5y-yEUDCK88FZWrGA 干货不迷路2021 年 9 月 8 日, ...

  3. [转帖]Skywalking介绍

    https://www.jianshu.com/p/ffa7ddcda4ab 微服务架构已经是一个很通用的系统架构,常见的技术栈如下图所示,这张架构图基本涵括了当前微服务体系下的各种技术栈,可能不同的 ...

  4. 使用yagmail发送邮件

    一.yagmail基本数据准备 1.终端下载yagmail:pip install yagmail 2.获取SMTP和密钥 我们以新浪邮箱为例,登录成功后进入设置页面,点击客户端pop/imap/sm ...

  5. k8s的内部服务通信

    首先看看 k8s 集群中内部各个服务互相访问的方法 Cluster IP Kubernetes以Pod作为应用部署的最小单位.Kubernetes会根据Pod的声明对其进行调度,包括创建.销毁.迁移. ...

  6. vue中keep-alive详细讲解

    场景 今天产品跑过来跟我说, 当我在A页面修改数据后,去B页面. 然后返回A页面.希望A页面保留我修改后的数据. 而不是数据又恢复最初的样子了.我心里想,尼玛,又要加班了? 看下面小粒子 数据被被重置 ...

  7. uni-app快速导入自己需要的插件

    在uni-app中快速导入自己需要的插件 在uni-app的官网上;找到自己需要的插件: 然后点击右侧顶部的[使用HX导入]这一步的前提是你必须要用自己的账好登录: 然后选择你要导入哪一个项目 然后就 ...

  8. 【代码分享】使用 avx512 + 查表法,优化凯撒加密

    作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢! cnblogs博客 zhihu Github 公众号:一本正经的瞎扯 关于凯撒加密,具体请看:https://en.wikipe ...

  9. windwos使用FRP方式

    FRP使用方法 流程图如下 建议查看流程图哦 访问FRP官方项目 https://freefrp.net 下面是windwos演示 进入网站选择客户端下载 客户端版本选择 windwos是adm64 ...

  10. Python通过SNMP监控网络设备

    前段时间,为了实现自动化巡检,我开发了自动化巡检工具,由于我的系统设备版本比较多,所以我是分别开发的客户端程序,服务端使用dll文件与客户端通信,服务端的dll在与python通信,通过Python丰 ...