http包详解
http包的作用及使用
go的http包是go的web编程的核心内容,go的web框架本质上都是基于http提供的组件进行再度封装。我们来看一下http基本的使用:
func main() {http.Handle("/get", GetVal())http.Handle("/hello", Hello())http.Handle("/demo", http.HandlerFunc(Demo))if err := http.ListenAndServe("0.0.0.0:9191", nil); err != nil {fmt.Println("err: %v", err)}
}func GetVal() http.HandlerFunc {return func(w http.ResponseWriter, r *http.Request) {val := "get\n"fmt.Fprintf(w, val)}
}func Hello() http.HandlerFunc {return func(w http.ResponseWriter, r *http.Request) {val := "hello\n"w.Write([]byte(val))}
}func Demo(w http.ResponseWriter, r *http.Request) {val := "get\n"fmt.Fprintf(w, val)
}
代码非常简单,就是为路由注册一个handler来处理请求并写入响应,我们来探究一下它的内部是如何实现的
源码分析
http包下的重要数据结构
ServerMux
type ServeMux struct {mu sync.RWMutex //保证读写路由表的并发安全m map[string]muxEntry
}
它是http包中的路由器组件,存储路由及handler的信息,能够通过路由规则快速匹配到对应的handler(高版本go使用的前缀树方式,低版本使用map的方式).
muxEntry
type muxEntry struct {explict boolhandler Handler
}
Handler
type Handler interface {ServeHTTP(ResponseWriter, *Request)
}
请求处理的业务逻辑函数,由用户自己定义,通过ServeHttp方法进行处理
HandlerFunc
type HandlerFunc func(ResponseWriter, *Request)// ServeHTTP calls f(w, r).
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {f(w, r)
}
它完全是为了方便用户使用,通过定义函数的方法替代定义结构体来注册handler
http包的工作流程——使用默认路由
注册路由
func Handle(pattern string, handler Handler) {DefaultServeMux.register(pattern, handler)
}//DefaultServeMux
func (mux *ServeMux) register(pattern string, handler Handler) {if err := mux.registerErr(pattern, handler); err != nil {panic(err)}
}func (mux *ServeMux) registerErr(patstr string, handler Handler) error {if patstr == "" {return errors.New("http: invalid pattern")}if handler == nil {return errors.New("http: nil handler")}if f, ok := handler.(HandlerFunc); ok && f == nil {return errors.New("http: nil handler")}pat, err := parsePattern(patstr)if err != nil {return fmt.Errorf("parsing %q: %w", patstr, err)}// Get the caller's location, for better conflict error messages.// Skip register and whatever calls it._, file, line, ok := runtime.Caller(3)if !ok {pat.loc = "unknown location"} else {pat.loc = fmt.Sprintf("%s:%d", file, line)}mux.mu.Lock()defer mux.mu.Unlock()// Check for conflict.if err := mux.index.possiblyConflictingPatterns(pat, func(pat2 *pattern) error {if pat.conflictsWith(pat2) {d := describeConflict(pat, pat2)return fmt.Errorf("pattern %q (registered at %s) conflicts with pattern %q (registered at %s):\n%s",pat, pat.loc, pat2, pat2.loc, d)}return nil}); err != nil {return err}mux.tree.addPattern(pat, handler)mux.index.addPattern(pat)mux.patterns = append(mux.patterns, pat)return nil
}
简单来说,但直接执行http.Handler方法注册路由时,就是将pattern及handler挂载到默认的ServeMux上。
DefaultServerMux会在挂载之前执行一系列的校验操作,并为了优化路由匹配性能引入一些复杂的数据结构和操作
server监听
入口-绑定port、监听请求
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)
}
循环阻塞、等待请求、协程处理
简化版代码
func (srv *Server) Serve(l net.Listener) error {baseCtx := context.Background()if srv.BaseContext != nil {baseCtx = srv.BaseContext(origListener)if baseCtx == nil {panic("BaseContext returned a nil context")}}var tempDelay time.Duration // how long to sleep on accept failurectx := context.WithValue(baseCtx, ServerContextKey, srv)for {rw, err := l.Accept()c := srv.newConn(rw)c.setState(c.rwc, StateNew, runHooks) // before Serve can returngo c.serve(connCtx)}
}
server会启动一个协程不断接收新来的请求,并新开一个协程处理请求来提高go的并发性和性能
请求处理逻辑
func (c *conn) serve(ctx context.Context) {//根据不同的配置往ctx注入信息// 针对不同的err信息进行处理//for循环不断读取conn的信息——针对长链接for {w, err := c.readRequest(ctx)//处理w和err,可能会推出循环serverHandler{c.server}.ServeHTTP(w, w.req) //处理请求//判断是否服用连接,不复用则退出循环}
}
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为空则使用我们之前说的defaultServerMux,否则使用我们自己的路由器处理请求
相关文章:
http包详解
http包的作用及使用 go的http包是go的web编程的核心内容,go的web框架本质上都是基于http提供的组件进行再度封装。我们来看一下http基本的使用: func main() {http.Handle("/get", GetVal())http.Handle("/hello", Hello())http.H…...
Reqable实战系列:Flutter移动应用抓包调试教程
Flutter应用网络请求调试一直是业内难题,原因在于Dart语言标准库的网络请求不会走Wi-Fi代理,常规通过配置Wi-Fi代理来抓包的方式行不通。这给我们日常开发测试造成了很大的阻碍,严重降低工作效率。因此写一篇教程,讲解如何使用Req…...
乾元通渠道商中标吴忠市自然灾害应急能力提升项目
近日,乾元通渠道商中标宁夏回族自治区吴忠市自然灾害应急能力提升项目,乾元通作为设备厂家,为项目提供通信指挥类装备(多链路聚合设备)QYT-X1。 青岛乾元通数码科技有限公司作为国家应急产业企业,深耕于数据…...
护网蓝队面试
一、sql注入分类 **原理:**没有对用户输入项进行验证和处理直接拼接到查询语句中 查询语句中插⼊恶意SQL代码传递后台sql服务器分析执行 **从注入参数类型分:**数字型注入、字符型注入 **从注入效果分:**报错注入、布尔注入、延时注入、联…...
【高考志愿】金融学
目录 一、金融学类专业概述 二、主要课程 三、就业前景与方向 四、适合人群 五、金融学学科排名 六、总结 高考志愿选择金融学,无疑是一个既充满挑战又极具前景的决策。金融学,作为经济学门类下的重要分支,不仅涵盖了广泛的金融领域知识…...
返利App的用户行为分析与数据驱动决策
返利App的用户行为分析与数据驱动决策 大家好,我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编,也是冬天不穿秋裤,天冷也要风度的程序猿!今天我们将深入探讨返利App中的用户行为分析与数据驱动决策的技术细节和实…...
python基础:高级数据类型:集合
1、集合的定义 集合是一个无序且无重复元素的列表。其定义与数学定义一致。其无序和不重复和字典特征类似,但是无“值”。 2、集合的创建 集合一般由列表创建,在初始化列表时保证其元素唯一性,即为集合。 创建方法:x set(list…...
idk17配置
只需要把zip包解压,然后配置环境变量: bin目录路径粘到path里面就好了 然后打开cmd窗口分别输入 java javac java -version 验证...
Java实现日志全链路追踪.精确到一次请求的全部流程
广大程序员在排除线上问题时,会经常遇见各种BUG.处理这些BUG的时候日志就格外的重要.只有完善的日志才能快速有效的定位问题.为了提高BUG处理效率.我决定在日志上面优化.实现每次请求有统一的id.通过id能获取当前接口的全链路流程走向. 实现效果如下: 一次查询即可找到所有关…...
你敢相信吗,AI绘画正在逐渐取代你的工作!
前言 在当今信息技术高速发展的时代,AI绘画技术的崛起已引起了广泛关注和讨论。许多人开始担心AI技术是否会逐渐取代传统绘画师的工作。人类无疑是感性的动物,创作出来的艺术作品常常带有浓郁的个人风格和情感。但AI绘画在某些方面的突破,使…...
博途PLC轴工艺对象随动误差监视功能
S7-1200PLC和V90总线伺服通过工艺对象实现定位控制时在组态工艺对象里有这样的随动误差监视功能介绍,关于这个功能,今天我们解读下,工艺对象组态编程可以参考下面文章链接: S7-1200PLC和V90总线伺服通过工艺对象实现定位控制(标准报文3应用)_v90工艺对象3号报文-CSDN博客文…...
《昇思25天学习打卡营第24天 | 昇思MindSporeResNet50图像分类》
24天 本节学习了使用ResNet50网络对CIFAR-10数据集进行分类。 步骤: 1.数据集准备与加载 2.构建网络 残差网络结构(Residual Network)是ResNet网络的主要亮点,ResNet使用残差网络结构后可有效地减轻退化问题,实现更深的网络结构设计&#x…...
糟糕的管理者都有这几个特征
在我们的职业生涯中,我们都期望能遇到一位英明睿智、引领团队走向辉煌的管理者。然而,现实往往并非总是如此美好,总会有一些管理能力差的人混迹其中,给团队带来诸多困扰。今天,我们就来看看糟糕的管理者身上都有哪些特…...
Python (Ansbile)脚本高效批量管理服务器和安全
1、简介 在现代 IT 基础设施中,管理大量服务器是一项复杂而繁琐的任务。特别是在检查服务器的存活状态以及 SSH 登录等任务上,手动操作非常耗时且容易出错。本文将介绍如何使用 Python 脚本实现对多台服务器的批量检查和管理,包括检查服务器…...
《数字图像处理与机器视觉》案例三 (基于数字图像处理的物料堆积角快速测量)
一、前言 物料堆积角是反映物料特性的重要参数,传统的测量方法将物料自然堆积,测量物料形成的圆锥表面与水平面的夹角即可,该方法检测效率低。随着数字成像设备的推广和应用,应用数字图像处理可以更准确更迅速地进行堆积角测量。 …...
Postman接口测试工具的原理及应用详解(四)
本系列文章简介: 在当今软件开发的世界中,接口测试作为保证软件质量的重要一环,其重要性不言而喻。随着前后端分离开发模式的普及,接口测试已成为连接前后端开发的桥梁,确保前后端之间的数据交互准确无误。在这样的背景…...
扛鼎中国AI搜索,天工凭什么?
人类的创作不会没有瓶颈,但AI的热度可不会消停。 大模型之战依旧精彩,OpenAI选择在Google前一天举行发布会,两家AI企业之间的拉扯赚足了热度。 反观国内,百模大战激发了大家对于科技变革的热切期盼,而如今行业已逐渐…...
【Ant Design Vue的更新日志】
🌈个人主页: 程序员不想敲代码啊 🏆CSDN优质创作者,CSDN实力新星,CSDN博客专家 👍点赞⭐评论⭐收藏 🤝希望本文对您有所裨益,如有不足之处,欢迎在评论区提出指正,让我们共…...
Elasticsearch环境搭建|ES单机|ES单节点模式启动|ES集群搭建|ES集群环境搭建
文章目录 版本选择单机ES安装与配置创建非root用户导入安装包安装包解压配置JDK环境变量配置single-node配置JVM参数后台启动|启动日志查看启动成功,访问终端访问浏览器访问 Kibana安装修改配置后台启动|启动日志查看浏览器访问 ES三节点集群搭建停止es服务域名配置…...
System.currentTimeMillis() JAVA 转C#
JAVA中的System.currentTimeMillis() ,指获取当前时间与1970年1月1日00:00:00 GMT之间所差的毫秒数的方法。 这个方法返回的是一个long类型的值,表示从某个固定时间点(通常是UNIX纪元,即1970年1月1日00:00:00 GMT)到…...
【Python】 -- 趣味代码 - 小恐龙游戏
文章目录 文章目录 00 小恐龙游戏程序设计框架代码结构和功能游戏流程总结01 小恐龙游戏程序设计02 百度网盘地址00 小恐龙游戏程序设计框架 这段代码是一个基于 Pygame 的简易跑酷游戏的完整实现,玩家控制一个角色(龙)躲避障碍物(仙人掌和乌鸦)。以下是代码的详细介绍:…...
RocketMQ延迟消息机制
两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数,对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后…...
如何将联系人从 iPhone 转移到 Android
从 iPhone 换到 Android 手机时,你可能需要保留重要的数据,例如通讯录。好在,将通讯录从 iPhone 转移到 Android 手机非常简单,你可以从本文中学习 6 种可靠的方法,确保随时保持连接,不错过任何信息。 第 1…...
Qt Http Server模块功能及架构
Qt Http Server 是 Qt 6.0 中引入的一个新模块,它提供了一个轻量级的 HTTP 服务器实现,主要用于构建基于 HTTP 的应用程序和服务。 功能介绍: 主要功能 HTTP服务器功能: 支持 HTTP/1.1 协议 简单的请求/响应处理模型 支持 GET…...
【单片机期末】单片机系统设计
主要内容:系统状态机,系统时基,系统需求分析,系统构建,系统状态流图 一、题目要求 二、绘制系统状态流图 题目:根据上述描述绘制系统状态流图,注明状态转移条件及方向。 三、利用定时器产生时…...
IT供电系统绝缘监测及故障定位解决方案
随着新能源的快速发展,光伏电站、储能系统及充电设备已广泛应用于现代能源网络。在光伏领域,IT供电系统凭借其持续供电性好、安全性高等优势成为光伏首选,但在长期运行中,例如老化、潮湿、隐裂、机械损伤等问题会影响光伏板绝缘层…...
pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)
目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关࿰…...
Caliper 负载(Workload)详细解析
Caliper 负载(Workload)详细解析 负载(Workload)是 Caliper 性能测试的核心部分,它定义了测试期间要执行的具体合约调用行为和交易模式。下面我将全面深入地讲解负载的各个方面。 一、负载模块基本结构 一个典型的负载模块(如 workload.js)包含以下基本结构: use strict;/…...
(一)单例模式
一、前言 单例模式属于六大创建型模式,即在软件设计过程中,主要关注创建对象的结果,并不关心创建对象的过程及细节。创建型设计模式将类对象的实例化过程进行抽象化接口设计,从而隐藏了类对象的实例是如何被创建的,封装了软件系统使用的具体对象类型。 六大创建型模式包括…...
tomcat指定使用的jdk版本
说明 有时候需要对tomcat配置指定的jdk版本号,此时,我们可以通过以下方式进行配置 设置方式 找到tomcat的bin目录中的setclasspath.bat。如果是linux系统则是setclasspath.sh set JAVA_HOMEC:\Program Files\Java\jdk8 set JRE_HOMEC:\Program Files…...
