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

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.Requesthttp.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官网的代码&#xff0c;但报错&#xff0c;Unexpected token’<’ 在js文件中// Button.stories.js|jsx import { Button } from ‘./Button’; export default { component: Button, }; /* *&#x1f447; Render functions are a framework specific featur…...

python 笔记 根据用户轨迹+基站位置,估计基站轨迹+RSRP

1 问题描述 已知用户实际的轨迹&#xff0c;和基站的位置&#xff0c;能不能得到用户所连接的基站&#xff0c;以及基站的信号强度RSRP&#xff1f; 1.1 几个假设 这里我们做几个假设&#xff1a; 每个用户有80%的概率连接最近的基站&#xff0c;有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 流量削峰 前言 …...

人工智能面面观

人工智能简介 人工智能&#xff08;Artificial Intelligence&#xff0c;简称AI&#xff09;是一门研究如何使计算机能够模拟和执行人类智能任务的科学和技术领域。它致力于开发能够感知、理解、学习、推理、决策和与人类进行交互的智能系统。人工智能的背景可以追溯到上世纪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计算机视觉&#xff0c;关注更多CV干货 论文已打包&#xff0c;点击进入—>下载界面 点击加入—>CV计算机视觉交流群 1.【基础网络架构&#xff1a;Transformer】Multi-entity Video Transformers for Fine-Grained Video Representation Learning 论文地址&…...

人工智能对当代生活的影响

人工智能&#xff08;AI&#xff09;是指通过模拟人类智能的方式&#xff0c;使机器能够执行某些需要智能的任务。随着技术的快速发展和应用的广泛推广&#xff0c;人工智能已经深入到我们的日常生活中&#xff0c;对我们的生活和社会产生了深远的影响。本文将探讨人工智能对当…...

笔记:如何搭建一套前端监控系统?(持续更新中)

数据敏感处理 数据加密&#xff0c;对涉及用户隐私的数据做到加密防护 独立部署&#xff0c;不和其它应用共享监控系统 不采集具体数据&#xff0c;只采集用户操作数据 错误采集 Runtime Error: JS运行错误&#xff0c;可通过error监听器捕获 load Error: 资源加载错误&#x…...

在 Ubuntu 上安装最新版的 Calibre

目录 前言 方法1&#xff1a;从 Ubuntu 的仓库安装 Calibre 卸载 Calibre 方法2&#xff1a;获取最新版本的 Calibre 卸载 Calibre 结语 前言 Calibre 是一款自由开源的电子书软件。下面介绍如何在 Ubuntu Linux 上安装它。 作为电子书管理的瑞士军刀&#xff0c;Calibre …...

docker基础学习笔记

文章目录 Docker简介Linux下安装DockerDocker常用命令Docker网络Docker存储docker-composedockerfile制作镜像私有仓库镜像导入导出参考 Docker简介 定义&#xff1a;Docker是一个开源的应用容器引擎优势&#xff1a; 一键部署&#xff0c;开箱即用&#xff1a;容器使用基于im…...

Could not resolve all files for configuration ‘:app:androidJdkImage‘.

在使用./gradlew build编译项目时候遇到了该问题&#xff0c;整体错误如下: * 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个村庄&#xff0c;编号从1到N&#xff0c;你应该建造一些道路&#xff0c;使每个村庄都可以相互连接。 两个村A和B是相连的&#xff0c;当且仅当A和B之间有一条道路&#xff0c;或者存在一个村C使得在A和C之间有一条道路&#xff0c;并…...

flutter 无法从H5 WebView 访问摄像头和录音权限

AndroidManifest.xml需要在 中添加以下权限&#xff1a; <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支持桌面多路由配置&#xff0c;新开窗口弹窗开启路…...

高精度算法总结

高精度加法 题目链接&#xff1a; https://www.acwing.com/activity/content/problem/content/825/ 代码模版&#xff1a; #include <iostream> #include <vector>using namespace std;// C A B vector<int> add(vector<int> &A, vector<…...

EMQX-5.3.1单机集群部署并基于Nginx实现负载均衡

本例单机集群部署使用三个节点&#xff0c;分别为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…...

KubeSphere 容器平台高可用:环境搭建与可视化操作指南

Linux_k8s篇 欢迎来到Linux的世界&#xff0c;看笔记好好学多敲多打&#xff0c;每个人都是大神&#xff01; 题目&#xff1a;KubeSphere 容器平台高可用&#xff1a;环境搭建与可视化操作指南 版本号: 1.0,0 作者: 老王要学习 日期: 2025.06.05 适用环境: Ubuntu22 文档说…...

前端倒计时误差!

提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...

linux 错误码总结

1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...

Spring AI 入门:Java 开发者的生成式 AI 实践之路

一、Spring AI 简介 在人工智能技术快速迭代的今天&#xff0c;Spring AI 作为 Spring 生态系统的新生力量&#xff0c;正在成为 Java 开发者拥抱生成式 AI 的最佳选择。该框架通过模块化设计实现了与主流 AI 服务&#xff08;如 OpenAI、Anthropic&#xff09;的无缝对接&…...

pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)

目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关&#xff0…...

【分享】推荐一些办公小工具

1、PDF 在线转换 https://smallpdf.com/cn/pdf-tools 推荐理由&#xff1a;大部分的转换软件需要收费&#xff0c;要么功能不齐全&#xff0c;而开会员又用不了几次浪费钱&#xff0c;借用别人的又不安全。 这个网站它不需要登录或下载安装。而且提供的免费功能就能满足日常…...

深入浅出深度学习基础:从感知机到全连接神经网络的核心原理与应用

文章目录 前言一、感知机 (Perceptron)1.1 基础介绍1.1.1 感知机是什么&#xff1f;1.1.2 感知机的工作原理 1.2 感知机的简单应用&#xff1a;基本逻辑门1.2.1 逻辑与 (Logic AND)1.2.2 逻辑或 (Logic OR)1.2.3 逻辑与非 (Logic NAND) 1.3 感知机的实现1.3.1 简单实现 (基于阈…...

【网络安全】开源系统getshell漏洞挖掘

审计过程&#xff1a; 在入口文件admin/index.php中&#xff1a; 用户可以通过m,c,a等参数控制加载的文件和方法&#xff0c;在app/system/entrance.php中存在重点代码&#xff1a; 当M_TYPE system并且M_MODULE include时&#xff0c;会设置常量PATH_OWN_FILE为PATH_APP.M_T…...

STM32---外部32.768K晶振(LSE)无法起振问题

晶振是否起振主要就检查两个1、晶振与MCU是否兼容&#xff1b;2、晶振的负载电容是否匹配 目录 一、判断晶振与MCU是否兼容 二、判断负载电容是否匹配 1. 晶振负载电容&#xff08;CL&#xff09;与匹配电容&#xff08;CL1、CL2&#xff09;的关系 2. 如何选择 CL1 和 CL…...

python读取SQLite表个并生成pdf文件

代码用于创建含50列的SQLite数据库并插入500行随机浮点数据&#xff0c;随后读取数据&#xff0c;通过ReportLab生成横向PDF表格&#xff0c;包含格式化&#xff08;两位小数&#xff09;及表头、网格线等美观样式。 # 导入所需库 import sqlite3 # 用于操作…...