Gee教程2.上下文Context
先来看看Gin框架的简单例子
func main() {engine := gin.Default()engine.GET("/", func(c *gin.Context) {c.String(http.StatusOK, "hello World!")})//监听并启动服务,默认 http://localhost:8080/engine.Run()
}//我们自己写的
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.Run("localhost:10000")
}
对比我们自己写的,Hander方法的参数变成了*gin.Context。
那么这版的主要修改策略是:
- 将
路由(Router)独立出来,方便之后增强。 - 设计
上下文(Context),封装 Request 和 Response ,并提供对 JSON、HTML 等返回类型的支持。
设计Context
必要性
1.web服务,基本就是根据客户的请求*http.Request,构造回应客户的响应http.ResponseWriter。但是这两个对象提供的接口粒度比较细。比如要构造一个完整的响应,需要考虑消息头和消息体,而消息头包含了状态码,消息类型等。那每次构造回复,都要写这些设置的代码。所以,如果不进行有效的封装,那么使用该框架的用户就需要写大量繁琐重复的代码。
通俗点说,就是要让使用框架的用户尽量少写重复的代码,少写代码可以实现同样的功能。
用返回JSON数据进行比较,来感受下封装前后的变化。
封装之前
engine.GET("/", func(w http.ResponseWriter, req *http.Request) {obj := map[string]any{"name": "abc","age": 20,}w.Header().Set("Content-Type", "application/json")w.WriteHeader(http.StatusOK)encoder := json.NewEncoder(w)if err := encoder.Encode(obj); err != nil {http.Error(w, err.Error(), 500)}})
封装后
engine.GET("/", func(c *gee.Context) {c.JSON(http.StatusOK, gee.H{"username": c.PostForm("username"),"password": c.PostForm("password"),})})
2.针对使用场景,封装*http.Request和http.ResponseWriter的方法,简化了相关接口的调用,这只是设计Context的原因之一。
对应框架来说,还需要支撑额外的功能。例如,之后要解析动态路由/hello/:name,参数:name的值放在哪里?Context随着每一个请求的出现而产生,请求的结束而销毁,和当前请求的强相关的信息都应由Context承载。每一个HTTP请求就会带有一个Context。
因此,设置Context结构,扩展性和复杂性都留在了内部,从而简化了接口。而路由的处理函数,以及之后要实现的中间件,参数都统一使用Context实例。Context就像一次会话的百宝箱,可以找到任何东西。
Context的实现
type H map[string]anytype Context struct {Wrtier http.ResponseWriterReq *http.RequestPath stringMethod string//响应的状态码StatusCode int
}func newContext(w http.ResponseWriter, req *http.Request) *Context {return &Context{Wrtier: w,Req: req,Path: req.URL.Path,Method: req.Method,}
}func (c *Context) PostForm(key string) string {return c.Req.FormValue(key)
}func (c *Context) Query(key string) string {return c.Req.URL.Query().Get(key)
}func (c *Context) Status(code int) {c.StatusCode = codec.Wrtier.WriteHeader(code)
}func (c *Context) SetHeader(key string, value string) {c.Wrtier.Header().Set(key, value)
}//以下是快速构造Sring/Data/JSON/HTML响应的方法
func (c *Context) String(code int, format string, values ...any) {c.SetHeader("Content-Type", "text/plain")c.Status(code)c.Wrtier.Write([]byte(fmt.Sprintf(format, values...)))
}func (c *Context) JSON(code int, obj any) {c.SetHeader("Content-Type", "application/json")c.Status(code)encoder := json.NewEncoder(c.Wrtier)if err := encoder.Encode(obj); err != nil {http.Error(c.Wrtier, err.Error(), 500)}
}func (c *Context) Data(code int, data []byte) {c.Status(code)c.Wrtier.Write(data)
}func (c *Context) HTML(code int, html string) {c.SetHeader("Content-Type", "text/html")c.Status(code)c.Wrtier.Write([]byte(html))
}
代码开头,给map[string]any起了别名H,构建JSON数据时候,使用gee.H显得更加简洁。
- Context目前包含了
http.ResponseWriter和*http.Request,这样为路由函数的参数可以修改成(c *gee.Context)做准备。另外也提供了对Method和Path这两个常用属性的直接访问。 提供了访问Query和PostForm参数的方法- 提供了快速构造Sring/Data/JSON/HTML响应的方法,使用简便。
路由(Router)
将路由抽取出来,放到一个新的文件router.go,方便我们下次对router功能的增强,录入添加动态路由的支持。而router的hander方法做了一个调整,就是handler的参数变成了前面所说的*Context。
将路由单独抽离出来,那和路由相关的路由方法的操作也会在该文件内。
package geeimport "net/http"
//HandlerFunc的定义在gee.go文件中type router struct {handers map[string]HandlerFunc
}func newRouter() *router {return &router{handers: make(map[string]HandlerFunc)}
}// 添加路由
func (r *router) addRoute(method string, pattern string, handler HandlerFunc) {key := method + "-" + patternr.handers[key] = handler
}func (r *router) handle(c *Context) {key := c.Method + "-" + c.Pathif hander, ok := r.handers[key]; ok {hander(c)} else {c.String(http.StatusNotFound, "404 NOT FOUND: %s\n", c.Path)}
}
框架入口
gee.go
type Engine struct {router *router
}// 创建enginx实例
func New() *Engine {return &Engine{router: newRouter()}
}func (engine *Engine) addRoute(method string, pattern string, hander HandlerFunc) {engine.router.addRoute(method, pattern, hander)
}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) {c := newContext(w, req)engine.router.handle(c)
}
在将路由router相关的代码独立之后,gee.go相对简单了不少。其中最重要的还是通过实现了ServeHTTP接口,接管了所有的HTTP请求。
这版的改变主要的改变,添加了Context,把路由router独立开来。在此基础上,gee.go中最大变化的是在ServHTTP方法中。
在Context中说了,一个HTTP请求,就带有一个Context。所以一个HTTP请求到来后,就为这个请求创建一个Context实例。
独立router部分后,执行路由方法的代码也在router中了。而路由方法的参数也由(http.ResponseWriter, *http.Request)修改成(*Context)。所以,ServHTTP需要调用router.handle去执行对应的路由方法,并把*context传递进去,给该请求发送响应,由用户自己定义的,但都是调用Context中的api来实现的,例如返回string字符串,Context.String函数。
所以,Context承载了整个会话的生命周期。
测试
到这里,使用的样子已经和Gin相似了。来看看使用例子。
func main() {engine := gee.New()engine.GET("/", func(c *gee.Context) {c.String(http.StatusOK, "ok..")})engine.POST("/hello", func(c *gee.Context) {c.JSON(http.StatusOK, gee.H{"name": "abc","age": 32,})})engine.Run("localhost:10000")
}
执行 go run main.go查看效果

完整代码:https://github.com/liwook/Go-projects/tree/main/gee-web/2-context
相关文章:
Gee教程2.上下文Context
先来看看Gin框架的简单例子 func main() {engine : gin.Default()engine.GET("/", func(c *gin.Context) {c.String(http.StatusOK, "hello World!")})//监听并启动服务,默认 http://localhost:8080/engine.Run() }//我们自己写的 func main()…...
【从浅识到熟知Linux】基本指定之cat、more和less
🎈归属专栏:从浅学到熟知Linux 🚗个人主页:Jammingpro 🐟每日一句:写完这篇我要去吃晚饭啦!! 文章前言:本文介绍cat、more和less指令三种查看文件的用法并给出示例和截图…...
2018年7月24日 Go生态洞察:Go Cloud实现便携式云编程
🌷🍁 博主猫头虎(🐅🐾)带您 Go to New World✨🍁 🦄 博客首页——🐅🐾猫头虎的博客🎐 🐳 《面试题大全专栏》 🦕 文章图文…...
storyBook常见踩坑报错 和 解决
用StoryBook官网的代码,但报错,Unexpected token’<’ 在js文件中// Button.stories.js|jsx import { Button } from ‘./Button’; export default { component: Button, }; /* *👇 Render functions are a framework specific featur…...
python 笔记 根据用户轨迹+基站位置,估计基站轨迹+RSRP
1 问题描述 已知用户实际的轨迹,和基站的位置,能不能得到用户所连接的基站,以及基站的信号强度RSRP? 1.1 几个假设 这里我们做几个假设: 每个用户有80%的概率连接最近的基站,有20%的概率选择其他的基站连…...
RocketMQ 安装部署及应用场景记录
文章目录 前言一、RocketMQ简介1.1 整体架构 二、RocketMQ安装部署2.1 RocketMQ 下载2.2 修改 JVM 参数2.3 启动 NameServer 和 Broker2.4 验证发送和接受消息2.5 停止 NameServer 和 Broker2.6 配置全局环境 三、RocketMQ应用场景3.1 异步处理3.2 应用解耦3.3 流量削峰 前言 …...
人工智能面面观
人工智能简介 人工智能(Artificial Intelligence,简称AI)是一门研究如何使计算机能够模拟和执行人类智能任务的科学和技术领域。它致力于开发能够感知、理解、学习、推理、决策和与人类进行交互的智能系统。人工智能的背景可以追溯到上世纪50…...
vue-router的使用技巧
一、安装 npm install vue-router 二、引入 main.ts引入 import { createApp } from vue import App from ./App.vue import router from ./routerconst app createApp(App)app.use(router) app.mount(#app)三、定义路由文件 路由的参数 meta添加路由的其他参数 redire…...
CV计算机视觉每日开源代码Paper with code速览-2023.11.21
点击CV计算机视觉,关注更多CV干货 论文已打包,点击进入—>下载界面 点击加入—>CV计算机视觉交流群 1.【基础网络架构:Transformer】Multi-entity Video Transformers for Fine-Grained Video Representation Learning 论文地址&…...
人工智能对当代生活的影响
人工智能(AI)是指通过模拟人类智能的方式,使机器能够执行某些需要智能的任务。随着技术的快速发展和应用的广泛推广,人工智能已经深入到我们的日常生活中,对我们的生活和社会产生了深远的影响。本文将探讨人工智能对当…...
笔记:如何搭建一套前端监控系统?(持续更新中)
数据敏感处理 数据加密,对涉及用户隐私的数据做到加密防护 独立部署,不和其它应用共享监控系统 不采集具体数据,只采集用户操作数据 错误采集 Runtime Error: JS运行错误,可通过error监听器捕获 load Error: 资源加载错误&#x…...
在 Ubuntu 上安装最新版的 Calibre
目录 前言 方法1:从 Ubuntu 的仓库安装 Calibre 卸载 Calibre 方法2:获取最新版本的 Calibre 卸载 Calibre 结语 前言 Calibre 是一款自由开源的电子书软件。下面介绍如何在 Ubuntu Linux 上安装它。 作为电子书管理的瑞士军刀,Calibre …...
docker基础学习笔记
文章目录 Docker简介Linux下安装DockerDocker常用命令Docker网络Docker存储docker-composedockerfile制作镜像私有仓库镜像导入导出参考 Docker简介 定义:Docker是一个开源的应用容器引擎优势: 一键部署,开箱即用:容器使用基于im…...
Could not resolve all files for configuration ‘:app:androidJdkImage‘.
在使用./gradlew build编译项目时候遇到了该问题,整体错误如下: * What went wrong: Configuration cache state could not be cached: field generatedModuleFile of com.android.build.gradle.tasks.JdkImageInput bean found in field compilerArgumentProvider…...
GLP-1 , GLP-1R
-- 6VCB_GLP-1R G_protein, GLP-1 peptidea positive allosteric modulator...
【数据结构】F : 道路建设 (Ver. I)
F : 道路建设 (Ver. I) Description 有N个村庄,编号从1到N,你应该建造一些道路,使每个村庄都可以相互连接。 两个村A和B是相连的,当且仅当A和B之间有一条道路,或者存在一个村C使得在A和C之间有一条道路,并…...
flutter 无法从H5 WebView 访问摄像头和录音权限
AndroidManifest.xml需要在 中添加以下权限: <uses-permission android:name"android.permission.INTERNET"/> <uses-permission android:name"android.permission.CAMERA" /> <uses-permission android:name"android.per…...
electron27-react-mateos:基于electron+react18仿matePad桌面系统
基于Electron27React18ArcoDesign搭建桌面版OS管理系统。 electron-react-mateos 基于最新前端跨端技术栈electron27.xreact18arco-designzustand4sortablejs构建的一款仿制matePad界面多层级路由管理OS系统。 ElectronReactOS支持桌面多路由配置,新开窗口弹窗开启路…...
高精度算法总结
高精度加法 题目链接: https://www.acwing.com/activity/content/problem/content/825/ 代码模版: #include <iostream> #include <vector>using namespace std;// C A B vector<int> add(vector<int> &A, vector<…...
EMQX-5.3.1单机集群部署并基于Nginx实现负载均衡
本例单机集群部署使用三个节点,分别为node1、node2、node3 一、安装与配置 1 创建数据目录 mkdir -p node1/data node1/logs mkdir -p node2/data node2/logs mkdir -p mode3/data node3/logs 2 数据目录授权 chown 1000 node1/ node2/ node3/ chown 1000 n…...
网络六边形受到攻击
大家读完觉得有帮助记得关注和点赞!!! 抽象 现代智能交通系统 (ITS) 的一个关键要求是能够以安全、可靠和匿名的方式从互联车辆和移动设备收集地理参考数据。Nexagon 协议建立在 IETF 定位器/ID 分离协议 (…...
CMake基础:构建流程详解
目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...
select、poll、epoll 与 Reactor 模式
在高并发网络编程领域,高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表,以及基于它们实现的 Reactor 模式,为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。 一、I…...
什么是Ansible Jinja2
理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具,可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板,允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板,并通…...
uniapp 开发ios, xcode 提交app store connect 和 testflight内测
uniapp 中配置 配置manifest 文档:manifest.json 应用配置 | uni-app官网 hbuilderx中本地打包 下载IOS最新SDK 开发环境 | uni小程序SDK hbulderx 版本号:4.66 对应的sdk版本 4.66 两者必须一致 本地打包的资源导入到SDK 导入资源 | uni小程序SDK …...
零知开源——STM32F103RBT6驱动 ICM20948 九轴传感器及 vofa + 上位机可视化教程
STM32F1 本教程使用零知标准板(STM32F103RBT6)通过I2C驱动ICM20948九轴传感器,实现姿态解算,并通过串口将数据实时发送至VOFA上位机进行3D可视化。代码基于开源库修改优化,适合嵌入式及物联网开发者。在基础驱动上新增…...
ZYNQ学习记录FPGA(一)ZYNQ简介
一、知识准备 1.一些术语,缩写和概念: 1)ZYNQ全称:ZYNQ7000 All Pgrammable SoC 2)SoC:system on chips(片上系统),对比集成电路的SoB(system on board) 3)ARM:处理器…...
热门Chrome扩展程序存在明文传输风险,用户隐私安全受威胁
赛门铁克威胁猎手团队最新报告披露,数款拥有数百万活跃用户的Chrome扩展程序正在通过未加密的HTTP连接静默泄露用户敏感数据,严重威胁用户隐私安全。 知名扩展程序存在明文传输风险 尽管宣称提供安全浏览、数据分析或便捷界面等功能,但SEMR…...
【51单片机】4. 模块化编程与LCD1602Debug
1. 什么是模块化编程 传统编程会将所有函数放在main.c中,如果使用的模块多,一个文件内会有很多代码,不利于组织和管理 模块化编程则是将各个模块的代码放在不同的.c文件里,在.h文件里提供外部可调用函数声明,其他.c文…...
从实验室到产业:IndexTTS 在六大核心场景的落地实践
一、内容创作:重构数字内容生产范式 在短视频创作领域,IndexTTS 的语音克隆技术彻底改变了配音流程。B 站 UP 主通过 5 秒参考音频即可克隆出郭老师音色,生成的 “各位吴彦祖们大家好” 语音相似度达 97%,单条视频播放量突破百万…...
