当前位置: 首页 > news >正文

go语言接口之http.Handler接口

package httptype 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 float32func (d dollars) String() string { return fmt.Sprintf("$%.2f", d) }type database map[string]dollarsfunc (db database) ServeHTTP(w http.ResponseWriter, req *http.Request) {for item, price := range db {fmt.Fprintf(w, "%s: %s\n", item, price)}
}

        如果我们启动这个服务:

$ go build gopl.io/ch7/http1
$ ./http1 &

        以使用web浏览器来连接服务器,我们得到下面的输出:

$ go build gopl.io/ch1/fetch
$ ./fetch http://localhost:8000
shoes: $50.00
socks: $5.00

        目前为止,这个服务器不考虑URL只能为每个请求列出它全部的库存清单。更真实的服务器 会定义多个不同的URL,每一个都会触发一个不同的行为。让我们使用/list来调用已经存在的 这个行为并且增加另一个/price调用表明单个货品的价格,像这样/price?item=socks来指定一 个请求参数。

func (db database) ServeHTTP(w http.ResponseWriter, req *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) // 404fmt.Fprintf(w, "no such item: %q\n", item)return}fmt.Fprintf(w, "%s\n", price)default:w.WriteHeader(http.StatusNotFound) // 404fmt.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) // 404

        /price的case会调用URL的Query方法来将HTTP请求参数解析为一个map,或者更准确地说一 个net/url包中url.Values类型的多重映射。然后找到第一个item参数并查找它的价格。 如果这个货品没有找到会返回一个错误。 这里是一个和新服务器会话的例子:

$ go build gopl.io/ch7/http2
$ go build gopl.io/ch1/fetch
$ ./http2 &
$ ./fetch http://localhost:8000/list
shoes: $50.00
socks: $5.00
$ ./fetch http://localhost:8000/price?item=socks
$5.00
$ ./fetch http://localhost:8000/price?item=shoes
$50.00
$ ./fetch http://localhost:8000/price?item=hat
no such item: "hat"
$ ./fetch http://localhost:8000/help
no such page: /help

        显然我们可以继续向ServeHTTP方法中添加case,但在一个实际的应用中,将每个case中的 逻辑定义到一个分开的方法或函数中会很实用。此外,相近的URL可能需要相似的逻辑;例 如几个图片文件可能有形如/images/*.png的URL。因为这些原因,net/http包提供了一个请求 多路器ServeMux来简化URL和handlers的联系。一个ServeMux将一批http.Handler聚集到一 个单一的http.Handler中。再一次,我们可以看到满足同一接口的不同类型是可替换的:web 服务器将请求指派给任意的http.Handler 而不需要考虑它后面的具体类型。

        对于更复杂的应用,一些ServeMux可以通过组合来处理更加错综复杂的路由需求。Go语言目 前没有一个权威的web框架,就像Ruby语言有Rails和python有Django。这并不是说这样的框 架不存在,而是Go语言标准库中的构建模块就已经非常灵活以至于这些框架都是不必要的。 此外,尽管在一个项目早期使用框架是非常方便的,但是它们带来额外的复杂度会使长期的 维护更加困难。

        在下面的程序中,我们创建一个ServeMux并且使用它将URL和相应处理/list和/price操作的 handler联系起来,这些操作逻辑都已经被分到不同的方法中。然后我门在调用 ListenAndServe函数中使用ServeMux最为主要的handler。

func main() {db := database{"shoes": 50, "socks": 5}mux := http.NewServeMux()mux.Handle("/list", http.HandlerFunc(db.list))mux.Handle("/price", http.HandlerFunc(db.price))log.Fatal(http.ListenAndServe("localhost:8000", mux))
}type database map[string]dollarsfunc (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.URL.Query().Get("item")price, ok := db[item]if !ok {w.WriteHeader(http.StatusNotFound) // 404fmt.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 httptype HandlerFunc func(w ResponseWriter, 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有一个方便的HandleFunc方法,它帮我 们简化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))
}

        最后,一个重要的提示:web服务器在一个新的协程中调用每一 个handler,所以当handler获取其它协程或者这个handler本身的其它请求也可以访问的变量 时一定要使用预防措施比如锁机制。

相关文章:

go语言接口之http.Handler接口

package httptype Handler interface {ServeHTTP(w ResponseWriter, r *Request) }func ListenAndServe(address string, h Handler) error ListenAndServe函数需要一个例如“localhost:8000”的服务器地址,和一个所有请求都可以分 派的Handler接口实例。它会一直运…...

R语言 | 使用最简单方法添加显著性ggpubr包

本期教程原文:使用最简单方法添加显著性ggsignif包 本期教程 获得本期教程代码和数据,在后台回复关键词:20240605 小杜的生信笔记,自2021年11月开始做的知识分享,主要内容是R语言绘图教程、转录组上游分析、转录组下游…...

【Linux】shell脚本变量——系统变量、环境变量和用户自定义变量

系统变量 系统变量是由系统预设的,它们通常在系统启动时被加载,并对所有用户和所有shell实例都有效。这些变量通常控制着系统的行为和配置,例如PATH(命令搜索路径)、HOME(用户主目录)等。系统变…...

QWidget 属性——windowTitle·windowIcon·qrc

🐌博主主页:🐌​倔强的大蜗牛🐌​ 📚专栏分类:QT ❤️感谢大家点赞👍收藏⭐评论✍️ 文章目录 一、windowTitle二、windowIcon三、qrc 一、windowTitle windowTitle 是一个通常用于表示窗口标题…...

深入理解rtmp(一)之开发环境搭建

深入理解rtmp(一)之开发环境搭建 手机直播在15年的时候突然火起来,随着花椒,映客等出现,直播一下就出现在了风口,各个公司针对直播的战斗迅速打响,战斗过程比较短暂,随着许多公司的退出和死去,手机直播行业趋于稳定,直播服务时长也被传统的CDN厂商牢牢占据,后面大家又把精力投…...

java常用面试基础题

&与&&区别? &和&&都是逻辑运算符,都是判断两边同时真则为真,否则为假;但是&&当第一个条件不成之后,后面的条件都不执行了,而&则还是继续执行,直到整个条件…...

互联网摸鱼日报(2024-06-11)

互联网摸鱼日报(2024-06-11) 36氪新闻 雅诗兰黛,胆子也太大了 苹果WWDC终极前瞻:5大看点20大AI新功能,库克不能输的一战 瑞士清洁科技公司Enerdrape开发预制地热板,回收城市地下空间的浅层地热能和废热用于建筑物制热或制冷 | …...

中介子方程十二

X$XFX$XEXyXαXiX$XαXiXrXkXtXyX$XpXVX$XVXpX$XyXtXkXrXiXαX$XiXαXyXEX$XFX$XEXyXαXiX$XαXiXrXkXtXyX$XpXVX$XVXpX$XyXtXkXrXiXαX$XiXαXyXEX$XαXηXtXαX$XWXyX$XyXWX$XpXαXqXηX$XeXαXhX$XdX$XpX$XdX$XyXeXαX$XEXyXαXiX$XαXiXrXkXtXyX$XpXVX$XVXpX$XyXtXkXrXiXα…...

SLT简介【简单介绍SLT】

SLT简介 在c的学习当中STL的学习是一个很重要的一环,但是STL又是一个庞大的章节,因此这里我们先简单介绍一下STL,有助于后面我们对STL的学习,这里就是做一个简单的介绍,并无干货。 1.什么是STL STL(standard templa…...

vue实现pdf下载——html2canvas

html2canvas 官方文档https://html2canvas.hertzen.com/getting-started html2canvas 的原理是通过遍历DOM树,将每一个HTML元素转化为Canvas对象,并叠加到一起形成一张完整的图片或者PDF文件。 1. 安装插件 npm install html2canvas jspdf --save 2.使用(页面已经…...

安装docker+mysql的一些坑

yum -y install docker 提示missing signature 参考这里 https://www.8a.hk/news/content/8235.html 卸载旧的docker sudo yum remove docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-engine 安装…...

React Native采集数据离线存储、网络状态监控、加密上传、鉴权

在无网络环境下进行数据采集并在有网络时上传至服务器,同时确保数据的鉴权和加密,这一需求需要考虑多方面的实现细节。无论您选择原生开发还是使用React Native(甚至Expo),以下是如何实现这一需求的具体步骤和建议。 …...

网络数据库后端相关面试题(其三)

18, 传输控制协议tcp和用户数据报协议udp有哪些区别 第一,tcp是面向字节流的,基本的传输单位是tcp报文段;而udp是面向报文的,基本传输单位是用户数据报。 第二, tcp注重安全可靠性,连接双方在…...

Hadoop之HDFS分布式文件系统

HDFS简介 Hadoop Distributed File System (HDFS): HDFS 是 Hadoop 的分布式文件系统,它设计用于存储大量数据,并提供 高吞吐率的数据访问,通过将数据分块存储在多个节点上,实现数据的冗余存储和容错。 HDFS重要概念 HDFS 通过统一的命名空间目录树来定位文件; 另外,它…...

插入删除单链表指定结点-偷天换日法

王道说下面的代码有BUG,比如当删除的结点p在最后一个元素时,p->nextNULL; So *q NULL; q->data就是错误的,我认为加个判断就行 加个判断即可 /*看着是删除q了,从结果上看就是把p删除了 偷天换日法*/ bool DeleteNode(LNod…...

MybatisPlus代码生成器使用案例

针对数据库中的实体类表,自动生成相关的pojo类,mapper,service等 1. Get-Started 基于mybatisplus,idea下载mybatisplus插件 sql文件 /*!40101 SET OLD_CHARACTER_SET_CLIENTCHARACTER_SET_CLIENT */; /*!40101 SET NAMES utf8 …...

数学公式编辑器(前端预研)

数学公式输入wangeditor: vue2使用wangeditor实现数学公式和富文本编辑器 mathjax文档:MathJax: 让前端支持数学公式 mathjax识别数学公式vue中使用mathjax识别latex数学公式 数学公式编辑器:(少) https://github.com…...

架构设计-如何安全地传输密码

java web 项目中经常会遇到登录或注册的场景,如果查看浏览器的 network 网络请求时,用户的密码以明文方式传输,会造成很多安全隐患,这就涉及到密码如何安全传输的问题。 数据加密的重要性不言而喻,通用的加密技术有 哈希散列、对称加密、非对称加密。 哈希散列 哈希散列是…...

【库】nprogress 顶部进度条

yarn add nprogress router文件 前置路由添加启动 后置路由添加关闭 router.beforeEach((to, from, next) > { NProgress.start() next() }) router.afterEach(() > { NProgress.done() }) App.vue 文件 引入样式 <script setup> import "nprogress/npro…...

15、架构-可靠通讯之服务安全

概述 我们已经了解了与具体架构形式无关的业界主流安全概念和技术标准&#xff08;如TLS、JWT、OAuth 2等概念&#xff09;&#xff0c;在上一章节探讨了与微服务运作特点相适应的零信任安全模型。在本节中&#xff0c;我们将从实践和编码的角度出发&#xff0c;介绍在微服务时…...

告别臃肿OS!手把手教你将Zephyr蓝牙协议栈移植到资源受限MCU(基于Polling轮询架构)

从零构建极简蓝牙协议栈&#xff1a;Zephyr Polling架构在资源受限MCU的实战指南 当智能手环的PCB面积被压缩到硬币大小&#xff0c;当电子价签需要依靠纽扣电池运行三年&#xff0c;传统蓝牙协议栈的"豪华配置"突然成了奢侈品。在深圳华强北的某个研发实验室里&…...

AI 创作者指南:04.AI写作:从草稿到润色的全流程协作

第4篇AI写作:从草稿到润色的全流程协作 第一部分创意引擎学完,你现在灵感满池、选题稳稳、观点锋利,是不是已经跃跃欲试想动笔了?😊 来,正式进入第二部分:AI作为写作与表达助手! 今天第4篇——AI写作:从草稿到润色的全流程协作。 咱们还是老朋友喝茶模式:AI不是让你…...

Grok-1大模型实战指南:如何用5大核心模块构建企业级AI应用

Grok-1大模型实战指南&#xff1a;如何用5大核心模块构建企业级AI应用 【免费下载链接】grok-1 马斯克旗下xAI组织开源的Grok AI项目的代码仓库镜像&#xff0c;此次开源的Grok-1是一个3140亿参数的混合专家模型 项目地址: https://gitcode.com/GitHub_Trending/gr/grok-1 …...

别再傻傻分不清!STM32定时器里Prescaler和ClockDivision到底谁管心跳谁管滤波?

STM32定时器双频分频机制深度解析&#xff1a;从心跳节拍到信号滤波 第一次接触STM32定时器配置时&#xff0c;看到Prescaler和ClockDivision这两个参数&#xff0c;很多开发者都会产生疑惑——它们看起来都是在做"分频"这件事&#xff0c;为什么需要两个参数&#x…...

保姆级拆解:MIT-BEVFusion中Swin Transformer如何高效处理多相机图像(附代码逐行分析)

多相机BEV感知中的Swin Transformer实战&#xff1a;从原理到MIT-BEVFusion代码精要 在自动驾驶感知系统中&#xff0c;如何高效处理多相机输入并构建统一的鸟瞰视图&#xff08;BEV&#xff09;表征一直是核心挑战。本文将深入探讨Swin Transformer在多相机BEV感知中的创新应用…...

12个化学工具集成:如何用ChemCrow在5分钟内完成复杂化学分析

12个化学工具集成&#xff1a;如何用ChemCrow在5分钟内完成复杂化学分析 【免费下载链接】chemcrow-public Chemcrow 项目地址: https://gitcode.com/gh_mirrors/ch/chemcrow-public 还在为繁琐的化学计算和分子分析而烦恼吗&#xff1f;ChemCrow化学智能助手将彻底改变…...

Linux下用qemu-nbd挂载qcow2镜像的完整指南(含LVM/非LVM/ntfs场景)

Linux下用qemu-nbd挂载qcow2镜像的完整指南&#xff08;含LVM/非LVM/ntfs场景&#xff09; 当虚拟机突然崩溃或需要从镜像中提取关键数据时&#xff0c;直接挂载qcow2镜像往往是最直接的解决方案。不同于常规磁盘挂载&#xff0c;qcow2镜像可能包含复杂的存储结构——从简单的e…...

5G NR物理层实战:如何利用TS 38.211优化无线资源管理

5G NR物理层实战&#xff1a;TS 38.211无线资源管理优化指南 在5G网络部署的深水区&#xff0c;无线资源管理&#xff08;RRM&#xff09;的精细化程度直接决定了网络性能天花板。作为3GPP物理层协议集的核心文档&#xff0c;TS 38.211规范中隐藏着诸多未被充分挖掘的优化密钥—…...

学生党必备:AutoDL服务器+Pycharm远程开发极简配置(含学生认证技巧)

学生党高效开发指南&#xff1a;AutoDLPycharm远程开发全攻略 1. 低成本深度学习开发环境搭建 作为一名深度学习爱好者&#xff0c;最头疼的莫过于硬件资源不足。显卡价格居高不下&#xff0c;笔记本跑个MNIST都卡顿&#xff0c;更别提训练复杂模型了。好在云服务器为我们提供了…...

N_m3u8DL-RE:现代流媒体下载的终极解决方案

N_m3u8DL-RE&#xff1a;现代流媒体下载的终极解决方案 【免费下载链接】N_m3u8DL-RE 跨平台、现代且功能强大的流媒体下载器&#xff0c;支持MPD/M3U8/ISM格式。支持英语、简体中文和繁体中文。 项目地址: https://gitcode.com/GitHub_Trending/nm3/N_m3u8DL-RE 在当今…...