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://www.mzph.cn/bicheng/39704.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Post请求方式获取亚马逊商品详情数据API(实时更新,缓存数据)

亚马逊商品详情数据接口(Amazon Product Advertising API)是亚马逊为开发者提供的一种服务,允许他们通过编程方式访问亚马逊网站上的商品信息。这些信息可以包括商品的详细描述、价格、库存状态、客户评价等。以下将详细阐述如何使用亚马逊商…

还敢乱买智能猫砂盆?今天扒一扒糯雪、鸟语花香、CEWEY智能猫砂盆!

在这高科技迅速发展的时代,连猫咪用来拉屎的屎盆子也变成了全自动化,从普通的猫砂盆变成了智能猫砂盆,让铲屎官再也不用每天赶回家铲屎给猫整理烂摊子,实在是非常轻松。所以那个时候的我也果断扔掉了家里的猫砂盆,转而…

电子电路学习笔记(4)三极管

部分内容参考链接: 电子电路学习笔记(5)——三极管_三极管 箭头-CSDN博客 模拟电子技术基础笔记(4)——晶体三极管_集电结的单向导电性-CSDN博客 硬件基本功-36-三极管Ib电流如何控制Ic电流_哔哩哔哩_bilibili MOS…

AI:开发者的助手还是替代者?

在人工智能(AI)迅速发展的今天,它对软件开发者的影响是一个备受争议的话题。本文将从AI工具的现状、对开发者的影响,以及AI开发的未来三个方向,探讨AI是在帮助开发者还是取代他们。 AI工具的现状 AI工具已经渗透到软…

论文学习_A Large-scale Empirical Study on theVulnerability of Deployed IoT Devices

论文名称发表时间发表期刊期刊等级研究单位A Large-scale Empirical Study on the Vulnerability of Deployed IoT Devices 2020年IEEE TDSCCCF A佐治亚理工大学1. 引言 研究背景:物联网(IoT)已成为互联网连接的重要组成部分,为我们的日常生活带来了极大的便利。与此同时…

使用DC/AC电源模块时需要注意的事项

BOSHIDA 使用DC/AC电源模块时需要注意的事项 1. 仔细阅读和理解产品说明书:在使用DC/AC电源模块之前,应该仔细阅读和理解产品说明书,了解其性能特点、技术要求和使用方法,以确保正确使用和避免潜在的安全风险。 2. 选择适当的电…

源代码编译安装LAMP

Apache简介 主要特点 开放源代码,跨平台应用 支持多种网页编程程序 模块化设计,运行稳定,良好得安全性 软件版本 1.X 目前最高版本是1.3,运行稳定 向下兼容性较好,但缺乏一些较新得功能 2.X 目前最高版本是2.4 …

PDF处理篇:如何调整 PDF 图像的大小

将视觉效果无缝集成到 PDF 中的能力使它们成为强大的通信工具。然而,笨拙的图像大小会迅速扰乱文档的流程,阻碍清晰度和专业性。幸运的是,GeekerPDF 和Adobe Acrobat等流行的应用程序提供了用户友好的解决方案来应对这一挑战。这个全面的指南…

Google 发布了最新的开源大模型 Gemma 2,本地快速部署和体验

Gemma 2 是 Google 最新发布的开源大语言模型。它有两种规模:90 亿(9B)参数和 270 亿(27B)参数,分别具有基础(预训练)和指令调优版本,拥有 8K Tokens 的上下文长度&#…

Vue3 特点以及优势-源码解剖

Vue3 特点以及优势-Vue3.4源码解剖 Vue3 特点以及优势 1.声明式框架 命令式和声明式区别 早在 JQ 的时代编写的代码都是命令式的,命令式框架重要特点就是关注过程声明式框架更加关注结果。命令式的代码封装到了 Vuejs 中,过程靠 vuejs 来实现 声明式代…

线性代数中的“过定系统”和“欠定系统”

过定系统 在线性代数中,当方程式的数量大于未知数的数量时,我们通常称这样的系统为“过定系统”(Overdetermined System)。这种情况下,系统往往没有精确解,即不存在一组未知数的值能够同时满足所有的方程。…

关于 VuePress 的插件

插件就好比第三方功能,例如增加一个阅读进度条、增加光标效果等。VuePress 官网对插件的介绍:插件通常会为 VuePress 添加全局功能。 这里简单介绍几个本站用的插件吧! ‍ ‍ 插件就好比第三方功能,例如增加一个阅读进度条、增…

如何实现在短信链接中直接打开微信小程序

你是否有过这样的体验,收到一条短信,里面有一个链接,点击后就直接打开了微信,并且进入了一个小程序。这种神奇的功能是如何实现的呢?本文将为你揭晓答案。 利用微信URL Link 接口生成链接 要实现短信中的链接直接打开…

13.什么是Proxy?

Proxy 是一种代理服务器,它充当客户端和目标服务器之间的中间人,转发网络请求和响应。当客户端向目标服务器发送请求时,它首先发送给代理服务器,然后由代理服务器转发请求给目标服务器。代理服务器可以用于许多目的,包…

VSG虚拟同步发电机simulink建模与仿真

目录 1.课题概述 2.系统仿真结果 3.核心程序与模型 4.系统原理简介 5.完整工程文件 1.课题概述 VSG虚拟同步发电机simulink建模与仿真,虚拟同步发电机(Virtual Synchronous Generator, VSG)技术是电力电子领域的一项重要创新&#xff0c…

C++:const及引用的使用场景

for (const auto& row : matrix) { // ... } 在C中,对于for (const auto& row : matrix)这样的循环,加上引用(&)并不是必须的,但它通常是一个好习惯,尤其是当matrix中的元素(…

Golang 依赖注入设计哲学|12.6K 的依赖注入库 wire

一、前言 线上项目往往依赖非常多的具备特定能力的资源,如:DB、MQ、各种中间件,以及随着项目业务的复杂化,单一项目内,业务模块也逐渐增多,如何高效、整洁管理各种资源十分重要。 本文从“术”层面&#…

安全和加密常识(1)对称加密和非对称加密以及相应算法

文章目录 对称加密(Symmetric Encryption)非对称加密(Asymmetric Encryption)使用场景和优缺点对称加密和非对称加密是信息安全领域中两种重要的加密方式,它们分别使用不同的加密算法和密钥管理方式来保护数据的机密性。下面我来简单介绍一下它们及其相应的算法。 对称加…

js多线程解决方案Web Worker简单说明与实例介绍

Web Worker是JavaScript中的多线程解决方案,它允许在后台执行耗时的任务,而不会阻塞主线程。通过将任务发送给Web Worker,主线程可以继续执行其他操作,同时Web Worker在后台完成任务。 使用Web Worker的一般流程如下:…

爆火AI惨遭阉割,1600万美国年轻人集体「失恋」? Character AI被爆资金断裂,00后炸了

【新智元导读】最近,在美国00后中爆火的Character AI,竟然把聊天机器人对话模型给「阉割」了?愤怒的年轻人们冲进社区,抱怨的声浪快要掀翻天了!而这背后,似乎还有谷歌或Meta的授意。 美国当今最火爆的社交…