Go-计网,http,JSON和Gin框架
计网(基础)
5层网络模型
在计算机网络中,一般由5层网络模型提供网络服务:
5层网络模型是计算机网络的经典分层架构,每层负责不同的功能:
- 物理层 - 最底层,定义物理介质上的比特流传输。
- 数据链路层 - 管理相邻节点之间的数据传输,确保物理链路上的可靠性。
- 网络层 - 处理网络间路由和寻址,将数据从源主机发送到目的主机。核心协议是IP协议。
- 传输层 - 负责端到端的通信,确保数据可靠传输。主要协议有TCP(可靠连接)和UDP(无连接服务)。
- 应用层 - 最上层,直接面向用户应用程序,提供网络服务接口。常见协议包括HTTP(用于网页浏览)、FTP(文件传输)、DNS(域名解析)等。

Socket协议
服务器监听及响应的过程

socket : 创建网络通讯起点(监听嵌套字)
bind : 将socket绑定到特定的地址和端口
listen : 进入监听状态
三次握手建立连接
三次握手是TCP建立可靠连接的过程:
第一次握手:客户端发送SYN=1和序列号seq=x
- 目的:发起连接请求,表示”我想和你建立连接”
- 意义:检查客户端能否正常发送数据,防止无效请求
第二次握手:服务端响应SYN=1、ACK=1、seq=y、ack=x+1
- 目的:确认收到请求,并同步自己的状态
- 意义:确保服务端活跃且愿意通信
第三次握手:客户端发送ACK=1、seq=x+1、ack=y+1
- 目的:最终确认连接
- 意义:防止已失效的请求突然到达,建立可靠连接
四次挥手关闭连接
四次挥手是TCP安全关闭连接的过程:
第一次挥手:主动方发送FIN=1、seq=u
- 目的:请求关闭连接
第二次挥手:被动方响应ACK=1、ack=u+1
- 目的:确认关闭请求,但可能还有数据要发送
第三次挥手:被动方发送FIN=1、ACK=1、seq=w、ack=u+1
- 目的:被动方也准备关闭
第四次挥手:主动方响应ACK=1、ack=w+1
- 目的:最终确认完全关闭
URL/URI
- URI(统一资源标识符):资源的完整标识,如身份证号
- URL(统一资源定位符):URI的子集,提供资源位置,如家庭地址
- 格式:
协议://主机:端口/路径?查询参数#片段
HTTP基础
包:net/http
HTTP报文与请求-响应模型
请求-响应模型是HTTP通信的核心机制:客户端发送请求报文,服务器处理后返回响应报文
http请求报文
一个HTTP请求报文由请求行(request line) 、请求头部(header)、空行和请求数据4个部分组成。
(1)请求行
请求行是请求报文的起始部分,包含以下内容:
- HTTP方法:描述请求的动作(如GET、POST、PUT等)。
- 目标路径(URI):资源的标识符,不包括域名。
- HTTP版本:使用的HTTP协议版本(如HTTP/1.1)。
| 方法 | 功能 | 是否幂等 | 特点 |
|---|---|---|---|
| GET | 获取服务器上的资源(数据或页面)。 | 是 | - 数据通过 URL 传递 - 不应修改服务器状态 - 适合只读操作 |
| POST | 向服务器发送数据以创建资源或触发操作。 | 否 | - 数据在请求体中 - 用于表单提交、创建资源或触发逻辑 |
| PUT | 更新或创建服务器上的资源(完全替换目标资源)。 | 是 | - 数据在请求体中 - 更新时完全覆盖资源 - 常用于资源的创建或更新操作 |
| DELETE | 删除服务器上的指定资源。 | 是 | - 删除操作 - 调用多次对结果无影响 |
| PATCH | 更新服务器上的资源(部分更新)。 | 否 | - 对资源的部分字段进行修改 - 非幂等(取决于实现方式) |
| HEAD | 类似 GET,但不返回响应体,仅返回响应头。 | 是 | - 用于检查资源是否存在或获取元信息 |
| OPTIONS | 返回服务器支持的 HTTP 方法和选项。 | 是 | - 用于探测服务器支持的能力 - 不对资源状态产生影响 |
| TRACE | 回显收到的请求,主要用于调试和诊断。 | 是 | - 直接返回请求内容 - 不常用,可能存在安全隐患 |
| CONNECT | 用于建立隧道连接,通常用于 HTTPS。 | 否 | - 用于代理服务器,主要处理加密的 SSL/TLS 隧道 |
幂等操作的效果在执行一次和多次时是相同的
(2)请求头
请求头部由关键字/值对组成,每行一对
典型的请求头有:
● Host:请求的主机名,允许多个域名同处一个IP 地址,即虚拟主机;
● connection:连接方式(close 或 keepalive);
● Cookie:存储于客户端扩展字段,向同一域名的服务端发送属于该域的cookie;
(3) 空行
空行用于分隔请求头和请求体。如果没有请求体,空行直接结束报文。
(4) 请求体(可选)
请求体包含请求发送的数据,在某些方法(如POST、PUT)中使用。可以是表单数据,JSON数据或上传文件。
http响应报文
响应报文由状态行,响应头,空行,响应体组成
(1)状态行
状态行是响应报文的起始部分,包含以下内容:
- HTTP版本:服务器使用的HTTP版本(如HTTP/1.1)。
- 状态码:用数字表示请求的处理结果(如200、404)。
- 状态文本:对状态码的简短描述(如OK、Not Found)。
状态码:由3位数字组成,第一个数字定义了响应的类别
状态码总结表
| 类别 | 含义 | 常见状态码及描述 |
|---|---|---|
| 1xx | 信息性响应 | 100 Continue, 101 Switching Protocols |
| 2xx | 成功 | 200 OK, 201 Created, 204 No Content |
| 3xx | 重定向 | 301 Moved Permanently, 302 Found, 304 Not Modified |
| 4xx | 客户端错误 | 400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found |
| 5xx | 服务器错误 | 500 Internal Server Error, 502 Bad Gateway, 503 Service Unavailable |
(2) 响应头
常见响应头
- Date:消息产生的时间
- Age:(从最初创建开始)响应持续时间
- Server: 向客户端标明服务器程序名称和版本
(3) 空行
空行用于分隔响应头和响应体。如果没有响应体,空行直接结束报文。
(4) 响应体(可选)
响应体包含返回的数据内容,例如HTML页面、JSON数据或文件内容。
代码实现(了解)
了解完基本概念之后,我们可以从go语言中的http/tcp包来讲讲怎么启动一个服务器
1 | package main |
JSON基础
简介
JSON 指的是 JavaScript 对象表示法(JavaScript Object Notation)
其为一种轻量级的数据交换格式
可以被使用在多种编程语言中,且常用于前后端之间的数据传输
我们主要学习JSON文本信息存储格式
语法
- 数据在
键/值对中 - 数据由逗号
,分隔 - 使用斜杆
\来转义字符 - 大括号
{}保存对象 - 中括号
[]保存数组,数组可以包含多个对象
JSON 的两种结构:
- 对象:大括号
{}保存的对象是一个无序的名称/值对集合。一个对象以左括号{开始, 右括号}结束。每个”键”后跟一个冒号:,名称/值对使用逗号,分隔。 - 数组:中括号
[]保存的数组是值(value)的有序集合。一个数组以左中括号[开始, 右中括号]结束,值之间使用逗号,分隔。
代码示例
1 | //对象 |
Gin框架
尽管http 包虽然功能齐全,但编写完整的 Web 应用需要重复写大量的基础代码,Web框架对其进行了封装,提供了:
更强大的路由功能,更简洁的api,更方便的中间件支持,更快的开发效率
基础语法
gin.Default(): 创建一个包含基础中间件 (Logger, Recovery) 的 Gin 引擎。r.GET(path, handler): 定义一个处理 GET 请求的路由。path 是路径,handler 是一个 func(c *gin.Context) 类型的函数。c *gin.Context: 这是 Gin 的核心!它包含了请求和响应的所有信息和方法。c.JSON(httpStatus, data): 以 JSON 格式返回响应。http.StatusOK 是 200。gin.H 是创建 map[string]interface{} 的便捷方式。r.Run(): 启动 Web 服务器。
1 | package main |
运行后,打开浏览器或使用 curl 访问 ( http://localhost:8080/ping )
你应该会看到:
1 | { |
路由
路由是 Web 框架的基础,Gin 提供了非常灵活强大的路由功能
基础 HTTP 方法
1 | r.GET("/someGet", getting) |
路由参数
1 | // 匹配 /users/john, /users/123 等 |
访问
http://localhost:8080/users/Claran会得到{"user_id":"Claran"}
查询参数
查询参数是 URL ? 后面的键值对,例如 /search?query=gin&page=1
1 | package main |
http://localhost:8080/search?page=3&information=%E9%87%8D%E5%BA%86%E9%82%AE%E7%94%B5%E5%A4%A7%E5%AD%A6会得到
{"extra":"none","page":"3","information":"重庆邮电大学"}
路由分组
当有多个路由共享相同的前缀(例如 API 版本 /api/v1)或需要应用相同的中间件时,路由分组非常有用
1 | // 创建一个 /api/v1 的路由组 |
现在可以通过
/api/v1/users访问用户相关接口了
请求处理
获取表单数据(form-data)
表单,是一个用于手机用户输入信息并将其提交给服务器的数据格式
例如:username=Claran&password=123456
这个表单储存了username和password的信息
content-type :
application/x-www-form-urlencoded 或 multipart/form-data
在Gin框架中获取表单数据:
1 | package main |
JSON数据转换
Gin 可以轻松地将请求体中的 JSON 绑定到 Go 结构体
在结构体中,使用 json tag 指定 JSON 字段名,使用 binding tag 添加校验规则( 需要引入 go-playground/validator)
1 | package main |
中间件Middleware
为web项目的路由注册中间件,则在被注册路由提交请求/返回响应时,请求/响应数据会自动流过中间件,执行其中的方法
常见中间件比如:
- 日志记录
- 错误处理
- 鉴权
- . . .
注:
gin.Default()默认使用gin.Logger()和gin.Recovery()中间件
使用中间件:
全局使用
1 | r := gin.Default() |
路由组使用
1 | adminGroup := r.Group("/admin") |
单个路由使用
1 | r.GET("/special", AnotherMiddleware(), func(c *gin.Context) { /* ... */ }) |
自定义中间件
中间件函数必须返回 gin.HandlerFunc 类型
1 | // 一个简单的自定义日志中间件示例 |
中间件方法
c.Next: 阻塞当前中间件,调用后续的处理函数c.Abort: 中止执行,后续中间件和c.AbortWithStatusJSON: 终止并直接返回一个 JSON 响应c.Set(key, value)和c.Get(key): 在不同中间件中通过定义键值对传递数据
项目结构
在编写Web项目时,代码和逻辑会很复杂,需要做好结构管理使内容条目清晰
以 Register&Login 简单项目举例:
1 | ├── README.md |
- README.md:项目的说明文档
- api:接口层,在里面是详细的逻辑实现以及路由。
- dao:全名为 data access object,进行数据库操作。
- model:模型层,主要放数据库实例的结构体。
- utils:一些常用的工具函数,封装在这里减少代码的重复使用。
- go.mod:依赖管理
例如:
使用Postman测试API接口
postman是一款便捷的用于测试api接口的工具,可向url发送post/get等多种type的数据
这部分很简单,用一次就会了
如:
该操作向 http://localhost:8080/regitser 发送了表单数据:username=Claran&password=chr070309&email=big_fell_sans@163.com数据
并得到返回JSON数据:{"status":200,"msg":"User registered successfully"}