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

【7days-golang/gee-web/day02】设计Context-学习笔记

主要内容:Gee 框架如何设计和使用 Context 结构体来简化 Web 服务中的常见任务,尤其是响应构造(如 HTML、JSON 等),并通过封装 http.Request 和 http.ResponseWriter 对象提供更高效、简洁的接口。

之前的工作

  • 构建一个基本的框架来接收请求并提供路由功能。
    • 定义了一个结构体 gee.Engine,负责保存所有的路由和处理函数。每一个路由都与一个 HTTP 方法(例如 GET、POST)相关联。
  • 让开发者能够注册不同路径和方法的路由,并关联到处理函数。
    • 负责保存所有的路由和处理函数。每一个路由都与一个 HTTP 方法(例如 GET、POST)相关联。

代码编写

在gee包下新建context.go

创建 Context 结构体

目的:在 Context 中保存请求和响应对象,以及一些帮助方法来操作请求参数和构建响应。从而简化对常见操作的处理。

package gee

import "net/http"

type Context struct {
	// 请求和响应的相关信息
	Writer http.ResponseWriter
	Req    *http.Request
	// 帮助快速获取当前请求的路径和方法。
	Path   string
	Method string

	StatusCode int
}

// 工厂函数,负责创建新的 Context 实例,并填充请求相关信息。
func newContext(w http.ResponseWriter, req *http.Request) *Context {
	return &Context{
		Writer: w,
		Req:    req,
		Path:   req.URL.Path,
		Method: req.Method,
	}
}

封装请求参数

目的:我们需要在 Context 中提供方法(在 Context 中添加 Query 和 PostForm 方法)来访问请求的查询参数和表单数据。这样,开发者无需直接操作 http.Request 对象,而是通过 Context 提供的方法来获取数据。简化访问查询参数和表单数据的过程。

func (c *Context) Query(key string) string {
	return c.Req.URL.Query().Get(key)
}

func (c *Context) PostForm(key string) string {
	return c.Req.FormValue(key)
}

简化响应构建

Web 框架的核心任务之一是构建 HTTP 响应。我们需要提供简洁的方法来发送不同类型的响应,如字符串、JSON 和 HTML。(在 Context 中封装一些方法,例如 String、JSON 和 HTML,来快速生成响应。)

func (c *Context) Status(code int) {
	c.StatusCode = code
	c.Writer.WriteHeader(code)
}

func (c *Context) SetHeader(key string, value string) {
	c.Writer.Header().Set(key, value)
}

func (c *Context) String(code int, format string, values ...interface{}) { // interface{} 是 Go 中的空接口,它可以接收任何类型的数据(与 Python 或 Java 中的 Object 类似)。然后,方法内部可以通过 fmt.Sprintf 来格式化这些参数。
	// c.Writer.Header().Set("Content-Type", "text/plain")
	c.SetHeader("Content-Type", "text/plain")
	c.Status(code)
	c.Writer.Write([]byte(fmt.Sprintf(format, values...))) // values... 是将可变参数展开发送给 fmt.Sprintf,它会根据 format 字符串的格式符(如 %s、%d)将参数插入到字符串中。
}

func (c *Context) JSON(code int, obj interface{}) { // 通过使用空接口,JSON 方法可以处理任何类型的数据(如结构体、数组、切片、map 等),并将其序列化为 JSON 格式。
	c.SetHeader("Content-Type", "application/json")
	c.Status(code)
	encoder := json.NewEncoder(c.Writer) // 创建了一个新的 将 Go 对象转换为 JSON 的编码器(json.Encoder),它将会把 Go 对象编码为 JSON 格式,并写入到 c.Writer(相当于输出到HTTP响应)
	if err := encoder.Encode(obj); err != nil {
		http.Error(c.Writer, err.Error(), 500)
	}
}

func (c *Context) Data(code int, data []byte) {
	c.Status(code)
	c.Writer.Write(data)
}

func (c *Context) HTML(code int, html string) {
	c.SetHeader("Content-Type", "text/html")
	c.Status(code)
	c.Writer.Write([]byte(html))
}

补充:类型别名

type H map[string]interface{}

map[string]interface{} 是一个键值对类型的映射,键为 string 类型,值为 interface{} 类型。
interface{} 是 Go 中的 空接口,意味着这个 map 可以存储任何类型的值。简单来说,H 就是一个可以存储任意数据类型的字典。
用例:

c.JSON(http.StatusOK, gee.H{
    "username": c.PostForm("username"),
    "password": c.PostForm("password"),
})

这行代码中,gee.H{} 创建了一个类型为 gee.H 的字典(实际上是 map[string]interface{}),它包含了两个键值对。

运行与测试

总结

Context 设计的必要性

Web服务通常基于两个重要对象:http.Request 和 http.ResponseWriter。但是,这两个对象提供的接口粒度较细,并且对于常见的 Web 服务响应(如 HTML、JSON)来说,需要多次重复配置,容易出错。
比如,创建 JSON 响应时需要手动设置 HTTP 头信息、状态码等。如果没有封装这些常见操作,开发者每次都需要写大量重复的代码。因此,Context 提供了一个简化的接口,封装了这些常用操作,使得开发者只需要关注业务逻辑,不需要处理底层的 HTTP 细节。
框架将复杂的 HTTP 请求和响应操作封装在 Context 中,使得开发者只需要关注业务逻辑,提升开发效率。

语法

接收者(Receiver)是方法定义中的第一个参数,它指定了该方法是作用于哪个类型的实例上的。
在 Go 中,接收者可以是值接收者(Context)或指针接收者(*Context),指针接收者可以修改实例的字段。
c 是 Context 类型的接收者,意味着 JSON 方法是作用于 Context 类型的实例上的,而 c 让你能够在方法中访问和操作 Context 实例。
1. func (c *Context) 表示该方法使用一个指向 Context 类型的指针作为方法的接收者。使用指针作为方法的接收者可以避免结构体实例的拷贝,同时允许方法修改原始结构体的内容。如果将 c 定义为非指针类型(即 Context),那么方法会作用于该结构体的副本,而不是原始结构体。
- 在 Python 和 Java 中,方法通常是类的成员方法,使用 self(Python)或 this(Java)来指代实例。
- 在 Go 中,你可以通过结构体类型实例后面加上指针(如 *Context)来让方法对实例进行修改。
2. 在 Go 中,函数定义通常包括:
- 接收者(Receiver):它与类的方法不同,是关联到一个特定类型上的。Go 没有类的概念,所有的方法都是通过类型(如结构体)来定义的。
- 参数列表(Parameters):定义函数的输入,类似 Python 或 Java 中的参数。
- 返回值(Return Values):定义函数返回的值,可以是多个。
3. 总结:在 Go 中,函数签名包括了一个“接收者”部分,这部分在 Python 和 Java 中通常不需要显式地声明。接收者是一个与类型(如结构体)相关联的特殊参数,它类似于 Python 的 self 或 Java 的 this。你可以通过 *Context 指针接收者来允许方法修改 Context 类型的实例。


http://www.kler.cn/a/560539.html

相关文章:

  • 前端学习—HTML
  • 九九乘法表 matlab
  • JPA与存储过程的完美结合
  • Unity Mirror 从入门到入神(一)
  • Java Set实现类面试题
  • 【linux】文件与目录命令 - awk
  • PHP MySQL 创建数据库
  • 机器学习数学通关指南——微分中值定理和积分中值定理
  • 塔能物联运维助力智慧隧道安全升级——城市交通保障新力量
  • std::thread的同步机制
  • 计算机视觉算法实战——跌倒检测(主页有源码)
  • 山东大学软件学院nosql实验三
  • 一个Flutter跨4端开发的案例
  • 流媒体网络协议全解析:从实时传输到自适应流,如何选择最优方案?
  • 【C++设计模式】工厂方法设计模式:深入解析从基础到进阶
  • 云电脑接入DeepSeek?探讨ToDesk云电脑、海马云、顺网云的AI潜能
  • API技术深度解析:构建高效、安全与可扩展的接口服务
  • Linux下文件权限与安全
  • 使用 INFINI Console 配置集群监控 Webhook 通知指南
  • 正则化及其在机器学习中的作用