go标准库---net/http服务端
1、http简单使用
go的http标准库非常强大,调用了两个函数就能够实现一个简单的http服务:
func HandleFunc(pattern string, handler func(ResponseWriter, *Request))
func ListenAndServe(addr string, handler Handler) error
handleFunc注册一个路由和相应的处理函数,第一个参数表示注册的路由,第二个参数表示注册路由对应的处理函数;ListenAndServe用来启动http服务并监听,第一个参数是服务器地址,第二个参数表示使用的处理器。
下面是用这两个函数实现的简单的http服务:注册了一个“/”路由的处理函数,并在8080端口启动http服务,ListenAndServe第二个参数为空表示使用标准库默认的处理器,也可使用自定义处理器,传参即可。处理器的概念在下面标准库分析中进行介绍。
import ("net/http"
)func main() {http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {// TODO})http.ListenAndServe(":8080", nil)
}
2、http标准库分析
根据上面的两个函数来对http标准库展开分析
2.1、服务端数据结构
首先介绍下这两个函数涉及到的数据类型
(1)服务器对象,其中最核心的是Handler成员,表示整个http服务的路由器,存储路由路径对应到处理函数的映射,可自定义,例如第1小姐中的案例,没有自定义路由器对象,就会使用标准库提供的默认对象DefaultServeMux
type Server struct {Addr string // 地址 host:portHandler Handler // 处理器对象或路由器// ...
}
(2)Handler是一个接口,提供了ServeHTTP方法,用来将路由映射到相应的处理函数上
type Handler interface {ServeHTTP(ResponseWriter, *Request)
}
(3)路由器对象ServeMux,用来存储路由到处理函数的映射关系,该对象就是Handler接口的具体实现。
type serveMux struct {mu sync.RWMutexm map[string]muxEntryes []muxEntry // slice of entries sorted from longest to shortest.hosts bool // whether any patterns contain hostnames
}
(4)muxEntry就是一个映射关系单元
type muxEntry struct {h Handlerpattern string
}
2.2、HandleFunc流程
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {// TODO
})
根据上面的函数来分析标准库的执行流程,首先看HandleFunc相关的实现:使用默认的DefaultServeMux路由器对象,调用ServeMux的HandleFunc,最后路由的注册是在mux.handle中实现,其中mux.Handle(pattern, HandlerFunc(handler))中对处理器做了类型转换,HandlerFunc 类型实现了ServeHTTP方法,所以被该类型转换后的函数都是Handler对象的实例
var DefaultServeMux = &defaultServeMuxvar defaultServeMux ServeMuxtype HandlerFunc func(ResponseWriter, *Request)func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {f(w, r)
}func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {DefaultServeMux.HandleFunc(pattern, handler)
}func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {if handler == nil {panic("http: nil handler")}mux.Handle(pattern, HandlerFunc(handler))
}func (mux *ServeMux) Handle(pattern string, handler Handler) {mux.handle(pattern, handler)
}
进入到mux.handle中,会创建一个路由单元muxEntry对象,存储相应的路由和处理函数,其中对于根路径的存储需要做出特殊处理,在muxEntry中通过es存储,并按照顺序存储在muxEntry切片中,到此,已经完成了路由注册
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] = eif pattern[len(pattern)-1] == '/' {mux.es = appendSorted(mux.es, e)}if pattern[0] != '/' {mux.hosts = true}
}func appendSorted(es []muxEntry, e muxEntry) []muxEntry {n := len(es)i := sort.Search(n, func(i int) bool {return len(es[i].pattern) < len(e.pattern)})if i == n {return append(es, e)}es = append(es, muxEntry{}) copy(es[i+1:], es[i:]) es[i] = ereturn es
}
2.3、ListenAndServe流程
ListenAndServe先初始化一个Server对象,并绑定地址和路由器,调用Server的ListenAndServe方法,其中net.Listen("tcp", addr)用于创建一个监听套接字并开始监听指定网络地址上的连接,返回一个实现了Listener接口的对象。关键是srv.Serve()
func ListenAndServe(addr string, handler Handler) error {server := &Server{Addr: addr, Handler: handler}return server.ListenAndServe()
}func (srv *Server) ListenAndServe() error {if srv.shuttingDown() {return ErrServerClosed}addr := srv.Addrif addr == "" {addr = ":http"}ln, err := net.Listen("tcp", addr)if err != nil {return err}return srv.Serve(ln)
}
在srv.Serve(ln)中使用onceCloseListener 对Listener进行封装,防止被多次关闭,context.WithValue用来将srv服务器对象信息存储在context中,并使用for循环轮询等待连接,l.Accept()会阻塞等待,直到连接到达,并执行conn.serve函数。
type onceCloseListener struct {net.Listeneronce sync.OncecloseErr error
}type contextKey struct {name string
}ServerContextKey = &contextKey{"http-server"}func (srv *Server) Serve(l net.Listener) error {l = &onceCloseListener{Listener: l}defer l.Close()// ...ctx := context.WithValue(baseCtx, ServerContextKey, srv)for {rw, err := l.Accept()// ...connCtx := ctx// ...c := srv.newConn(rw)// ...go c.serve(connCtx)}
}
其中newConn会将Accept的返回的net.Conn封装成一个conn对象,对每个请求都会创建一个线程来处理,在conn.serve中会针对conn对象创建读写器并将内容置入缓冲区,在for中调用readRequest函数传入上下文,在readRequest中读取请求体req,并返回一个ResponseWriter的接口对象,用于向请求方返回响应,并在调用serverHandler的ServeHTTP方法
type conn struct {server *Serverrwc net.Conn// ...
}func (c *conn) serve(ctx context.Context) {c.remoteAddr = c.rwc.RemoteAddr().String()ctx = context.WithValue(ctx, LocalAddrContextKey, c.rwc.LocalAddr())ctx, cancelCtx := context.WithCancel(ctx)c.cancelCtx = cancelCtxdefer cancelCtx()c.r = &connReader{conn: c}c.bufr = newBufioReader(c.r)c.bufw = newBufioWriterSize(checkConnErrorWriter{c}, 4<<10)for {w, _ := c.readRequest(ctx)serverHandler{c.server}.ServeHTTP(w, w.req)w.finishRequest()...}
}
serverHandler的ServeHTTP方法用来根据路由分配handler,如果Server的Handler为空就是用默认的DefaultServerMux,对应上了文章一开始调用ListenAndServe的第二个参数,如果为空就使用默认路由器对象,最后调用路由器的ServeHTTP函数。
type serverHandler struct {srv *Server
}func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) {handler := sh.srv.Handlerif handler == nil {handler = DefaultServeMux}if !sh.srv.DisableGeneralOptionsHandler && req.RequestURI == "*" && req.Method == "OPTIONS" {handler = globalOptionsHandler{}}handler.ServeHTTP(rw, req)
}
接下来流程如下,依次调用返回命中的handler,如果没有命中,则采用模糊匹配命中,最后调用handler的ServeHTTP函数,因为注册路由时候的函数在注册时候被强转成HandleFunc函数类型,该类型是实现ServeHTTP方法的,所以执行handler的ServeHTTP方法就是执行注册路由是对应的处理函数。
func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) {h, _ := mux.Handler(r)h.ServeHTTP(w, r)
}func (mux *ServeMux) Handler(r *Request) (h Handler, pattern string) {// ...return mux.handler(host, r.URL.Path)
}func (mux *ServeMux) handler(host, path string) (h Handler, pattern string) {mux.mu.RLock()defer mux.mu.RUnlock()return mux.match(path)
}func (mux *ServeMux) match(path string) (h Handler, pattern string) {v, ok := mux.m[path]if ok {return v.h, v.pattern}for _, e := range mux.es {if strings.HasPrefix(path, e.pattern) {return e.h, e.pattern}}return nil, ""
}
相关文章:
go标准库---net/http服务端
1、http简单使用 go的http标准库非常强大,调用了两个函数就能够实现一个简单的http服务: func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) func ListenAndServe(addr string, handler Handler) error handleFunc注册一个路…...
Linux文件和目录常用命令
1.操作命令 查看目录内容 ls 切换目录 cd 创建和删除操作 touch rm mkdir 拷贝和移动文件 cp mv 查看文件内容 cat more grep 其他 echo 重定向 > 和 >> 管道 | 1.1 终端实用技巧 1>自动补全 在敲出 文件/目录/命令 的前几个字母之后,按下…...
【C++刷题】优选算法——链表
链表常用技巧和操作总结 常用技巧 画图 引入虚拟头节点 不要吝啬空间,大胆定义变量 快慢双指针常用操作 创建一个新节点 尾插 头插 两数相加 ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {int carry 0;ListNode* newHead new ListNode, *cur newHea…...
Flex和Bison
Flex和Bison是Linux和Unix环境下两个非常强大的工具,分别用于生成词法分析器和语法分析器。它们在编译器设计、文本处理等领域有着广泛的应用。下面我将详细介绍Flex和Bison的基本概念、功能、用法以及它们之间的关系。 一、Flex 1. 基本概念 Flex(其…...
Matlab-FPGA 小数转换为定点二进制小数脚本和转coe文件格式脚本
Matlab-FPGA 小数转换为定点二进制小数脚本: % 更新于2023年6月17日,修改旋转因子文件,不修改fpga %首先明确我们的二维FFT的数组维数,此为1024*8的二维矩阵,1024行,8列 column 1024; row 8; nk[]; Ncolumn*row; fo…...
逆向案例二十三——请求头参数加密,某区块链交易逆向
网址:aHR0cHM6Ly93d3cub2tsaW5rLmNvbS96aC1oYW5zL2J0Yy90eC1saXN0L3BhZ2UvNAo 抓包分析,发现请求头有X-Apikey参数加密,其他表单和返回内容没有加密。 直接搜索关键字,X-Apikey,找到疑似加密位置,注意这里…...
CSS 导航栏:设计、定制与优化
CSS 导航栏:设计、定制与优化 CSS(层叠样式表)是网页设计中不可或缺的一部分,它允许开发者通过定义样式来控制网页的布局和外观。在网页设计中,导航栏是一个关键元素,它帮助用户浏览网站并找到他们感兴趣的…...
JS 如何处理链接被用户点击中键的操作
今天在开发中遇到一个问题,在使用类似Bootstrap中的Tabs组件时,当在tab导航链接点击中键时会打开一个新的窗口访问链接,于是我尝试在别的普通链接上点击中键时也会如此,我猜测这是浏览器的默认行为。 由于我开发的是一个浏览器在…...
Android 11 使用HAL层的ffmpeg库(1)
1.frameworks/av/media目录下面的修改 From edd6f1374c1f15783d9920ebda22ea915e503775 Mon Sep 17 00:00:00 2001 From: GW00219471 <zhumingxingnoboauto.com> Date: Wed, 17 Jan 2024 15:16:10 0800 Subject: [PATCH] ?UTF-8?q?[V35CUX-4542]:E7A7BBE6A48Dcux20E8…...
友力科技数据中心搬迁方案
将当前运行机房中的所有设备、应用系统安全搬迁至新数据中心机房,实现平滑切换、平稳过渡,最大限度地降低搬迁工作对业务的影响。 为了确保企事业单位能够顺利完成数据中心机房搬迁工作,我们根据实际经验提供了4个基本原则,希望能…...
GitHub敏感信息扫描工具
目录 功能设计 技术实现 程序使用 文件配置 下载地址 功能设计 GitPrey是根据企业关键词进行项目检索以及相应敏感文件和敏感文件内容扫描的工具,其设计思路如下: 根据关键词在GitHub中进行全局代码内容和路径的搜索(in:file,path),将项目结果做项目信息去重整理得到…...
Linux云计算 |【第一阶段】ENGINEER-DAY4
主要内容: 配置Linux网络参数、配置静态主机名、查看/修改/激活/禁用网络连接、指定DNS、虚拟网络连接、虚拟机克隆、SSH客户端、SCP远程复制、SSH无密码验证(SERVICE-DAY5)、虚拟网络类型 一、网络参数配置 修改网卡配置文件主要是需要配置…...
C++与VLC制作独属于你的动态壁纸背景
文章目录 前言效果展示为什么要做他如何实现他实现步骤获取桌面句柄代码获取桌面句柄libvlc_media_player_set_hwnd函数 动态壁纸代码 总结 前言 在当今的数字世界中,个性化和自定义化的体验越来越受到人们的欢迎。动态壁纸是其中一种很受欢迎的方式,它…...
平凯星辰黄东旭出席 2024 全球数字经济大会 · 开放原子开源数据库生态论坛
7 月 5 日,以“开源生态筑基础,数字经济铸未来”为主题的 2024 全球数字经济大会——开放原子开源数据库生态论坛在北京成功举办。平凯星辰(北京)科技有限公司联合创始人黄东旭发表了题为《TiDB 助力金融行业关键业务系统实践》的…...
Mac OS 下安装 NVM,1秒教会你
1.下载 curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash或者wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash 2.安装成功后执行 nvm 提示 command not found 首先查看 ~/.bash_profile 文件是否存在&…...
搭建博客系统#Golang
WANLI 博客系统 项目介绍 基于vue3和gin框架开发的前后端分离个人博客系统,包含md格式的文本编辑展示,点赞评论收藏,新闻热点,匿名聊天室,文章搜索等功能。 点击跳转:Github 项目开源地址 功能展示 B 站…...
算法——滑动窗口(day6)
1004.最大连续1的个数 ||| 1004. 最大连续1的个数 III - 力扣(LeetCode) 题目解析: 这道题如果能转化为滑动窗口的话就会很简单,因为我们如果尝试去把0翻转为1再计数的话等到第2轮又得重新翻转回来,费时费力~ 那么我…...
推荐一款基于Spring Boot 框架开发的分布式文件管理系统,功能齐全,非常便捷(带私活源码)
前言 在数字化时代,文件管理是企业和个人用户的基本需求。然而,现有的文件管理系统往往存在一些痛点,如存储空间有限、文件共享困难、缺乏在线编辑功能、移动端适配性差等。这些问题限制了用户在不同设备和场景下的文件处理能力。 为了解决…...
Mysql-查询
1.基本查询 //查询所有内容 select * from 表名;//查询指定字段 select 字段1,字段2,字段3.....from 表名;//查询时给字段起别名 select 字段1 as 别名1 , 字段2 as 别名2 ... from 表名;//去重查询 select distinct 字段列表 from 表名; …...
广东科学技术职业学院计算机学院领导一行莅临泰迪智能科技参观交流
7月17日,广东科学技术职业学院计算机学院副院长张军、计算机学院副书记吴国庆、计算机学院大数据教学部部长谢文达、科技与校企合作部副部长黄相杰、科技与校企合作部副部长吴胜兵莅临广东泰迪智能科技股份有限公司产教融合实训基地参观交流,泰迪智能科技…...
nodejs+vue基于springboot的高校创新创业项目评审系统
目录技术选型与架构设计数据库设计后端实现要点前端开发流程系统集成与测试部署方案项目技术支持可定制开发之功能创新亮点源码获取详细视频演示 :文章底部获取博主联系方式!同行可合作技术选型与架构设计 后端采用Spring Boot框架提供RESTful API服务&…...
nodejs+vue基于springboot的巨会玩剧本杀服务平台管理系统
目录技术栈选择系统模块划分数据库设计关键API示例(Spring Boot)前端交互示例(Vue Axios)实时通信方案部署架构测试策略项目里程碑项目技术支持可定制开发之功能创新亮点源码获取详细视频演示 :文章底部获取博主联系方…...
交稿前一晚!9个AI论文工具全场景通用测评,助你高效完成毕业论文与科研写作
在学术研究与论文写作中,效率与质量的平衡始终是科研人员面临的核心挑战。随着AI技术的不断成熟,各类AI论文工具层出不穷,但如何在众多选择中找到真正契合自身需求的解决方案,成为亟待解决的问题。为此,笔者基于2026年…...
DeepChat完整指南:构建你的全能AI助手平台
DeepChat完整指南:构建你的全能AI助手平台 【免费下载链接】deepchat DeepChat - 连接强大AI与个人世界的智能助手 | DeepChat - A smart assistant that connects powerful AI to your personal world 项目地址: https://gitcode.com/GitHub_Trending/dee/deepch…...
高性能Python HTTP客户端urllib3架构设计与性能优化实战指南
高性能Python HTTP客户端urllib3架构设计与性能优化实战指南 【免费下载链接】urllib3 urllib3 is a user-friendly HTTP client library for Python 项目地址: https://gitcode.com/gh_mirrors/ur/urllib3 urllib3作为Python生态中最成熟的HTTP客户端库之一,…...
SAP增强实战:如何精准控制销售订单可用性检查中的寄售库存占用
1. 理解寄售库存与可用性检查的核心矛盾 在SAP系统中处理销售订单时,寄售库存和自有库存的混用问题经常让业务人员头疼。想象这样一个场景:你的仓库里明明没有现货,但系统却自动从供应商寄存在你这里的货物中扣减数量——这就像未经允许拿了邻…...
OFA-COCO蒸馏版实战教程:使用Gradio封装为可共享的在线Demo服务
OFA-COCO蒸馏版实战教程:使用Gradio封装为可共享的在线Demo服务 1. 引言 你有没有遇到过这样的场景?手头有一堆图片,需要快速为它们配上文字描述,无论是用于内容管理、辅助创作,还是为视障人士提供信息。一张张手动编…...
深入解析Java中的hashCode与equals方法:从理论到应用
在Java编程中,hashCode()和equals()方法是非常重要的,它们被广泛应用于对象比较和哈希表等数据结构中。这两个方法之间存在着紧密的联系,了解它们的工作原理和用法对于掌握Java编程至关重要。01重要方法概述◉ hashCode与equals简介在Java编程…...
从开发到灾备:一文读懂软件部署的六大核心环境
1. 开发环境(DEV):代码诞生的第一站 开发环境是程序员的主战场,这里就像厨师的厨房,所有新鲜代码都在这里诞生。我习惯用本地Docker搭建开发环境,这样能完美复现线上环境配置。举个例子,用VSCod…...
Ostrakon-VL-8B识别极限测试:超大规模菜品图库检索效果
Ostrakon-VL-8B识别极限测试:超大规模菜品图库检索效果 最近在做一个餐饮相关的项目,需要从几十万张菜品图片里快速找到相似的菜。这听起来简单,但实际操作起来,你会发现很多模型在“大海捞针”时表现并不稳定。要么是特征提取不…...
