Gee教程1.HTTP基础

标准库启动web服务

Go语言内置了 net/http库,封装了HTTP网络编程的基础的接口。这个Web 框架便是基于net/http的。我们先回顾下这个库的使用。

package mainimport ("fmt""log""net/http"
)func main() {//可以写成匿名函数(lambda表达式),handler echoes r.URL.Pathhttp.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {fmt.Fprintf(w, "URL.Path = %q\n", req.URL.Path)})http.HandleFunc("/hello", helloHandler)log.Fatal(http.ListenAndServe("localhost:10000", nil))//log.Fatal(http.ListenAndServe(":10000", nil)) 也可以写成这样的,没有写到ip
}// handler echoes r.URL.Header
func helloHandler(w http.ResponseWriter, req *http.Request) {for k, v := range req.Header {fmt.Fprintf(w, "Header[%q] = %q\n", k, v)}
}

来看看效果

 这里设置了两个路由 / 和hello,分别绑定了一个匿名函数和helloHandler。之后根据不同的http请求会调用不同的处理函数。结果如上如图。

main 函数的最后一行,是用来启动 Web 服务的。

第一个参数是ip地址,localhost:110000表示在 本地地址的10000端口监听。而第二个参数则代表处理所有的HTTP请求的实例,nil 代表使用标准库中的默认实例处理。第二个参数,则是我们基于net/http标准库实现Web框架的入口

实现http.Handler接口

来看看源码

package httptype Handler interface {ServeHTTP(w ResponseWriter, r *Request)
}func ListenAndServe(address string, h Handler) error// Serve a new connection.
func (c *conn) serve(ctx context.Context) {//...............serverHandler{c.server}.ServeHTTP(w, w.req)//.................
}

通过源码可以看到,Handler是一个接口类型,需要实现ServeHTTP方法。

http.ListenAndServe中会调用ServerHTTP方法,即是调用h.ServerHTTP。

即是说,只要传入任何实现了 ServerHTTP 接口的实例,所有的HTTP请求,就都交给了该实例处理了。所以我们要自己写一个实现该接口的实例,让所有的HTTP请求由自己来写。

那接下我们实现一个Handler。

package mainimport ("fmt""log""net/http"
)type Engine struct{}func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {switch req.URL.Path {case "/":fmt.Fprintf(w, "URL.Path = %q\n", req.URL.Path)case "/hello":for k, v := range req.Header {fmt.Fprintf(w, "Header[%q]= %q\n", k, v)}default:fmt.Fprintf(w, "404 NOT FOUND: %s\n", req.URL)}
}func main() {engine := &Engine{}log.Fatal(http.ListenAndServe("localhost:10000", engine))
}

我们定义了一个空的结构体Engine,实现了方法ServeHTTP。

ServeHTTP方法有两个参数,一是ResponseWriter,这个是用来构建对客户端的http回复响应。二是Request ,该对象包含了该HTTP请求的所有的信息,比如请求地址、请求Header和Body等信息。

而在main函数中,我们给ListenAndServe方法的第二个参数传入了engine实例。至此,我们走出了实现web框架的第一步,即是将所有的HTTP请求都转向了我们自己的处理逻辑。

而在实现Enginx之前,我们调用 http.HandleFunc实现了路由和helloHandler的映射,也就是只能针对具体的路由来写对应的处理逻辑。而在实现Engine之后,我们可以拦截所有的HTTP请求,拥有了统一的控制入口。这样我们可以自由定义路由映射的规则,也可以统一添加一些处理逻辑,例如日志、异常处理等。

Gee框架的雏形

我们再整理之前所讲的,搭建出整个框架的雏形。

 进行初始化

 主要文件是main.go和gee.go

先看下是如何使用的

mian.go

package mainimport ("fmt""geeV1/gee""net/http"
)func main() {engine := gee.New()engine.GET("/", func(w http.ResponseWriter, req *http.Request) {fmt.Fprintf(w, "URL.Path = %q\n", req.URL.Path)})engine.POST("/hello", func(w http.ResponseWriter, req *http.Request) {for k, v := range req.Header {fmt.Fprintf(w, "Header[%q] = %q\n", k, v)}})engine.Run("localhost:10000")
}

和gin框架的使用是相似的。使用New()创建 gee 的实例,使用 GET(),POST()方法添加路由,最后使用Run()启动Web服务。这里的路由,只是静态路由,不支持/hello/:name这样的动态路由,之后会实现动态路由。

接下来看看是如何实现的

gee.go

package geeimport ("fmt""net/http"
)type HandlerFunc func(http.ResponseWriter, *http.Request)type Engine struct {router map[string]HandlerFunc //添加对应的路由和路由函数的映射
}// 创建enginx实例
func New() *Engine {return &Engine{router: make(map[string]HandlerFunc)}
}// 添加路由
func (engine *Engine) addRoute(method string, pattern string, handler HandlerFunc) {key := method + "-" + patternengine.router[key] = handler
}func (engine *Engine) GET(pattern string, handler HandlerFunc) {engine.addRoute("GET", pattern, handler)
}
func (engine *Engine) POST(pattern string, handler HandlerFunc) {engine.addRoute("POST", pattern, handler)
}func (engine *Engine) Run(addr string) error {return http.ListenAndServe(addr, engine)
}func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {key := req.Method + "-" + req.URL.Pathfmt.Println(key)if handler, ok := engine.router[key]; ok {handler(w, req)} else {w.WriteHeader(http.StatusNotFound) //添加状态码,404fmt.Fprintf(w, "404 NOT FOUND: %s\n", req.URL.Path)}
}

那么gee.go就是重头戏了。我们重点介绍一下这部分的实现。

对比之前的空结构体Engine,其结构体添加了router 路由映射表。

key 由请求方法静态路由地址构成,例如GET-/GET-/helloPOST-/hello,这样针对相同的路由,如果请求方法不同,可以映射不同的处理方法(Handler),value 是用户映射的处理方法(用户自己写的)。

main函数中使用GET()等添加路由,其GET()等方法就是调用了addRoute,把路由和对应的handler添加到router中。

Run方法是调用了http.ListenAndServe(addr, engine)。所有的HTTP请求都会首先进入ServeHTTP中。Engine实现的 ServeHTTP 方法的作用就是,解析请求的路径,查找路由映射表,如果查到,就执行注册的处理方法。如果查不到,就返回 404 NOT FOUND 。

执行go run main.go查看效果

 至此,整个web框架的原型已经出来了。我们实现了路由映射表,提供了用户注册静态路由的方法,也包装了启动服务的函数。当然,当前我们实现的功能也没有比net/http标准库更强大。之后,会陆续将动态路由、中间件等功能添加上去。

完整代码:https://github.com/liwook/Go-projects/tree/main/gee-web/1-http-base

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/171878.shtml

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

相关文章

【数据结构初阶】树,二叉树

树,二叉树 1.树概念及结构1.1树的概念1.2 树的相关概念1.3 树的表示1.4 树在实际中的运用(表示文件系统的目录树结构) 2.二叉树概念及结构2.1概念2.2现实中的二叉树2.3 特殊的二叉树2.4 二叉树的性质2.5 二叉树的存储结构 1.树概念及结构 1.…

STM32-SPI3控制MCP3201、MCP3202(Sigma-Delta-ADC芯片)

STM32-SPI3控制MCP3201、MCP3202(Sigma-Delta-ADC芯片) 原理图手册说明功能方框图引脚功能数字输出编码与实值的转换分辨率设置与LSB最小和最大输出代码(注) 正负符号寄存器位MSB数字输出编码数据转换的LSB值 将设备输出编码转换为…

SQL JOIN 子句:合并多个表中相关行的完整指南

SQL JOIN JOIN子句用于基于它们之间的相关列合并来自两个或更多表的行。 让我们看一下“Orders”表的一部分选择: OrderIDCustomerIDOrderDate1030821996-09-1810309371996-09-1910310771996-09-20 然后,看一下“Customers”表的一部分选择&#xff…

单片机学习5——外部中断程序

#include<reg52.h>unsigned char a; sbit lcden P3^4;void main() {lcden0;EA1;EX01;IT00;a0xF0; //点亮4位小灯while(1){P1a;} }//中断服务程序 void ext0() interrupt 0 // 0 表示的是外部中断源0 {a0x0f; // 中断处理完&#xff0c;再返回主…

2018年10月4日 Go生态洞察:参与2018年Go公司问卷调查

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

系列十八、Spring bean线程安全问题

一、概述 我们知道Spring中的bean&#xff0c;默认情况下是单例的&#xff0c;那么Spring中的bean是线程安全的吗&#xff1f;这个需要分情况考虑&#xff0c;bean中是否存在成员变量&#xff1f;bean中的成员变量是怎么处理的&#xff1f;...&#xff0c;针对bean的状态会有不…

【C++】类和对象——拷贝构造和赋值运算符重载

上一篇我们讲了构造函数&#xff0c;就是对象实例化时会自动调用&#xff0c;那么&#xff0c;我们这里的拷贝构造在形式上是构造函数的一个重载&#xff0c;拷贝构造其实也是一种构造函数&#xff0c;那么我们就可以引出这里的规则 1.拷贝构造函数的函数名必须与类名相同。 2.…

数据结构——带头循环双向链表(List)

1、带头双向循环链表介绍 在上一篇博客中我们提到了链表有三个特性&#xff0c;可以组合成为8种不同类型的链表。单链表是其中比较重要的一种&#xff0c;那么这次我们选择和带头双向循环链表会会面&#xff0c;这样我们就见识过了所有三种特性的呈现。 带头双向循环链表&#…

HONOR荣耀MagicBook 15 2021款 锐龙版R5(BMH-WFQ9HN)原厂Windows11预装OEM系统含F10智能还原

链接&#xff1a;https://pan.baidu.com/s/1faYtC5BIDC2lsV_JSMI96A?pwdj302 提取码&#xff1a;j302 原厂系统Windows11.22H2工厂模式安装包,含F10一键智能还原&#xff0c;自带所有驱动、出厂主题壁纸、系统属性专属LOGO标志、Office办公软件、荣耀 电脑管家等预装程序 …

process control 化学工程 需要用到MATLAB的Simulink功能

process control 化学工程 需要用到MATLAB的Simulink功能 所有问题需要的matlab simulink 模型 WeChat: ye1-6688 The riser tube brings in contact the recirculating catalyst with the feed oil, which then vaporizes and splits to lighter components as it flows up th…

服务器下db(数据库)的执行

1、查看 select * from xxxx&#xff08;表名&#xff09; where xxx&#xff08;列表&#xff09;1 and.......正常写就行 2、插入 如果你想要在 SELECT INSERT INTO … SELECT 语句中将部分列保持不变,只改变一两列的值,可以在 语句中直接设置目标列的值,而其他列从源表中…

【C++】类型转换 ③ ( 重新解释类型转换 reinterpret_cast | 指针类型数据转换 )

文章目录 一、重新解释类型转换 reinterpret_cast1、指针数据类型转换 - C 语言隐式类型转换报错 ( 转换失败 )2、指针数据类型转换 - C 语言显示类型强制转换 ( 转换成功 )3、指针数据类型转换 - C 静态类型转换 static_cast ( 转换失败 )4、指针数据类型转换 - C 重新解释类型…

Simulink 的代数环

代数环, 就是由于模型的输出反馈到模块或子系统先的某个输入端, 如果这个输入是直接馈入的, 那么二者在同一个采样点内需得到求解, 但又互相依赖, 哪一方都不能完成求解过程, 使得解算器无法解算导致错误产生, 这样的情况称为代数环。 一旦 Simulink 遇到代数环, 将根据 Confi…

python环境搭建-yolo代码跑通-呕心沥血制作(告别报错no module named torch)

安装软件 安装过的可以查看有没有添加环境变量 好的! 我们发车! 如果你想方便快捷的跑通大型项目,那么必须安装以下两个软件: 1.pycharm2.anaconda对应作用: pycharm:专门用来跑通python项目的软件,相当于一个编辑器,可以debug调试,可以接受远程链接调试!anaconda:专…

2023年初中生古诗文大会复选最后6天备考策略和更新的在线模拟题

今天是2023年11月26日&#xff0c;星期日&#xff0c;距离2023年第八届上海市中学生古诗文大会复选&#xff08;复赛&#xff09;还有六天&#xff08;2023年12月2日上午举办&#xff09;&#xff0c;相信各位晋级的小学霸们正在繁忙的学业之余抓紧备考。 为了帮助孩子们更有效…

thinkphp最新开发的物业管理系统 缴费管理、停车管理、收费管理、值班管理

物业费&#xff0c;水电燃气费&#xff0c;电梯费&#xff0c;租金&#xff0c;临时收费等多种收费规则完全自定义&#xff0c;账单自动生成&#xff0c;无需人工计算 实时数据互通&#xff1a;一键报事报修&#xff0c;购买车辆月卡&#xff0c;管理家人信息&#xff0c;参加物…

idea spring initializr创建项目报错

闲来无事就想搞个项目练练手&#xff0c;没想到直接给我卡在项目创建上了&#xff0c;一个个问题最终迎刃而解。 1.上来就给我报了个maven的错 未解析的插件: ‘org.apache.maven.plugins:maven-resources-plugin:3.3.1’ 不慌&#xff0c;应该是maven的路径有问题&#xff0c…

Redis缓存淘汰策略

Redis缓存淘汰策略 1、各种面试题 生产上你们的redis内存设置多少?如何配置、修改redis的内存大小如果内存满了你怎么办&#xff1f;redis清理内存的方式?定期删除和惰性删除了解过吗&#xff1f;redis缓存淘汰策略有哪些?分别是什么?你用哪个?redis的LRU了解过吗?请手…

AMESim与MATLAB联合仿真demo

本文是AMESim与MATLAB联合仿真的demo&#xff0c;记录一下如何进行联合仿真。 AMESim与MATLAB联合仿真可以大幅度提高工作效率。 author&#xff1a;xiao黄 缓慢而坚定的生长 csdn:https://blog.csdn.net/Python_Matlab?typeblog主页传送门 博主的联合仿真环境如下&#xff…

代码随想录算法训练营 ---第四十三天

前言&#xff1a; 今天同样是01背包问题&#xff0c;今天详细学习了背包问题在各种场景下的应用。今天一道也没做出来&#xff0c;有点废。好难啊&#xff01;就是思路不太清晰&#xff0c;不知道如何去做&#xff0c;看了题解后感觉原来如此&#xff0c;但是想不出来。今天做…