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

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)到…...

Cesium1.95中高性能加载1500个点

一、基本方式&#xff1a; 图标使用.png比.svg性能要好 <template><div id"cesiumContainer"></div><div class"toolbar"><button id"resetButton">重新生成点</button><span id"countDisplay&qu…...

【网络安全产品大调研系列】2. 体验漏洞扫描

前言 2023 年漏洞扫描服务市场规模预计为 3.06&#xff08;十亿美元&#xff09;。漏洞扫描服务市场行业预计将从 2024 年的 3.48&#xff08;十亿美元&#xff09;增长到 2032 年的 9.54&#xff08;十亿美元&#xff09;。预测期内漏洞扫描服务市场 CAGR&#xff08;增长率&…...

从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路

进入2025年以来&#xff0c;尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断&#xff0c;但全球市场热度依然高涨&#xff0c;入局者持续增加。 以国内市场为例&#xff0c;天眼查专业版数据显示&#xff0c;截至5月底&#xff0c;我国现存在业、存续状态的机器人相关企…...

Nuxt.js 中的路由配置详解

Nuxt.js 通过其内置的路由系统简化了应用的路由配置&#xff0c;使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...

Python爬虫(二):爬虫完整流程

爬虫完整流程详解&#xff08;7大核心步骤实战技巧&#xff09; 一、爬虫完整工作流程 以下是爬虫开发的完整流程&#xff0c;我将结合具体技术点和实战经验展开说明&#xff1a; 1. 目标分析与前期准备 网站技术分析&#xff1a; 使用浏览器开发者工具&#xff08;F12&…...

AI,如何重构理解、匹配与决策?

AI 时代&#xff0c;我们如何理解消费&#xff1f; 作者&#xff5c;王彬 封面&#xff5c;Unplash 人们通过信息理解世界。 曾几何时&#xff0c;PC 与移动互联网重塑了人们的购物路径&#xff1a;信息变得唾手可得&#xff0c;商品决策变得高度依赖内容。 但 AI 时代的来…...

C++使用 new 来创建动态数组

问题&#xff1a; 不能使用变量定义数组大小 原因&#xff1a; 这是因为数组在内存中是连续存储的&#xff0c;编译器需要在编译阶段就确定数组的大小&#xff0c;以便正确地分配内存空间。如果允许使用变量来定义数组的大小&#xff0c;那么编译器就无法在编译时确定数组的大…...

GruntJS-前端自动化任务运行器从入门到实战

Grunt 完全指南&#xff1a;从入门到实战 一、Grunt 是什么&#xff1f; Grunt是一个基于 Node.js 的前端自动化任务运行器&#xff0c;主要用于自动化执行项目开发中重复性高的任务&#xff0c;例如文件压缩、代码编译、语法检查、单元测试、文件合并等。通过配置简洁的任务…...

LOOI机器人的技术实现解析:从手势识别到边缘检测

LOOI机器人作为一款创新的AI硬件产品&#xff0c;通过将智能手机转变为具有情感交互能力的桌面机器人&#xff0c;展示了前沿AI技术与传统硬件设计的完美结合。作为AI与玩具领域的专家&#xff0c;我将全面解析LOOI的技术实现架构&#xff0c;特别是其手势识别、物体识别和环境…...

深度剖析 DeepSeek 开源模型部署与应用:策略、权衡与未来走向

在人工智能技术呈指数级发展的当下&#xff0c;大模型已然成为推动各行业变革的核心驱动力。DeepSeek 开源模型以其卓越的性能和灵活的开源特性&#xff0c;吸引了众多企业与开发者的目光。如何高效且合理地部署与运用 DeepSeek 模型&#xff0c;成为释放其巨大潜力的关键所在&…...