10 | 基于 Gin 实现 HTTP 服务器
提示:
- 所有体系课见专栏:Go 项目开发极速入门实战课;
- 欢迎加入 云原生 AI 实战 星球,12+ 高质量体系课、20+ 高质量实战项目助你在 AI 时代建立技术竞争力(聚焦于 Go、云原生、AI Infra);
- 本节课最终源码位于 fastgo 项目的 feature/s07 分支;
- 更详细的课程版本见:Go 项目开发中级实战课:20 | Web 服务器实现:如何基于 Gin 实现一个 HTTP 服务器?
在 Go 项目开发中,开发场景最多的是开发一个 Web 服务器,Web 服务器种类有很多,例如:HTTP 服务器、RPC 服务器、WebSocket 服务器等。
其中,HTTP 服务器是最常需要开发的服务器类型。HTTP 服务器,其实就是一个对外提供 API 接口的 Web 服务器。API 接口其实是有规范的,当前用的最多的 REST 规范。
所以,本节课,就来看下如何快速开发一个 REST API 服务器。
REST Web 框架选择
要编写一个 RESTful 风格的 API 服务器,你可以自己调用 net/http包手动实现一个,但这样耗时而且效果也不好。所以企业开发中,通常会使用 Web 框架来开发一个 REST 服务器。
Web 框架有很多,例如:Gin、Hertz、Echo、Eiber 等。当前使用最多的是 Gin 框架。Gin 框架很轻量,并且具有以下优点:高性能、扩展性强、稳定性强、相对而言比较简洁(查看 性能对比)。关于 Gin 的更多介绍可以参考 Gin 官网。
开发一个简单的 REST 服务器
使用 Gin 框架开发一个 REST 服务器分为以下几步:
- 配置 REST 服务器(配置监听端口);
- 创建 Gin 引擎;
- 设置 Gin 路由;
- 启动 Gin 服务器。
步骤 1:配置 REST 服务器
修改 cmd/fg-apiserver/app/options/options.go 文件,给 ServerOptions 结构体添加 Addr 配置项。代码变更如下:
package optionsimport ("fmt""net""strconv"...
)type ServerOptions struct {...Addr string `json:"addr" mapstructure:"addr"`
}// NewServerOptions 创建带有默认值的 ServerOptions 实例.
func NewServerOptions() *ServerOptions {return &ServerOptions{...Addr: "0.0.0.0:6666",}
}// Validate 校验 ServerOptions 中的选项是否合法.
// 提示:Validate 方法中的具体校验逻辑可以由 Claude、DeepSeek、GPT 等 LLM 自动生成。
func (o *ServerOptions) Validate() error {...// 验证服务器地址if o.Addr == "" {return fmt.Errorf("server address cannot be empty")}// 检查地址格式是否为host:port_, portStr, err := net.SplitHostPort(o.Addr)if err != nil {return fmt.Errorf("invalid server address format '%s': %w", o.Addr, err)}// 验证端口是否为数字且在有效范围内port, err := strconv.Atoi(portStr)if err != nil || port < 1 || port > 65535 {return fmt.Errorf("invalid server port: %s", portStr)}return nil
}// Config 基于 ServerOptions 构建 apiserver.Config.
func (o *ServerOptions) Config() (*apiserver.Config, error) {return &apiserver.Config{...Addr: o.Addr,}, nil
}
上面的代码给 ServerOptions 结构体添加了 Addr 字段,用来保存 Web 服务器的监听地址,默认地址设置为:0.0.0.0:6666。
在 Validate方法中,添加了对 Addr 字段的校验,检查了 Addr字段的格式是否合法,端口的范围是否正确。在实际开发中,你可以根据实际需要添加更多的校验。
在 Config 方法中,需要将应用的 Addr 配置字段赋值给运行时配置。所以还要在运行时配置中添加 Addr 字段。修改 internal/apiserver/server.go 文件中的 Config 结构体添加 Addr 字段:
type Config struct {...Addr string
}
步骤 2:创建 Gin 引擎
修改 internal/apiserver/server.go 文件,在 Server 结构体中新增 *http.Server 类型的字段 srv,并在 NewServer方法中实例化 srv,变更代码如代码清单 10-1 所示:
代码清单 10-1
package apiserverimport (..."net/http"..."github.com/gin-gonic/gin"...
)
...
// Server 定义一个服务器结构体类型.
type Server struct {...srv *http.Server
}// NewServer 根据配置创建服务器.
func (cfg *Config) NewServer() (*Server, error) {// 创建 Gin 引擎engine := gin.New()// 注册 404 Handler.engine.NoRoute(func(c *gin.Context) {c.JSON(http.StatusNotFound, gin.H{"code": "PageNotFound", "message": "Page not found."})})// 注册 /healthz handler.engine.GET("/healthz", func(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"status": "ok"})})// 创建 HTTP Server 实例httpsrv := &http.Server{Addr: cfg.Addr, Handler: engine}return &Server{cfg: cfg, srv: httpsrv}, nil
}
在 NewServer 方法中,通过 gin.New() 创建了一个 Gin 引擎实例 engine。并通过 engine 中的方法给 engine 设置了 REST 路由和中间件。
代码中的 engine.NoRoute 方法调用,设置了当 Gin 找不到匹配的请求路径时返回的信息:
{"code":"PageNotFound","message":"Page not found."}
NewServer 方法的最后部分,创建了标准库的 http.Server 实例,并将配置好的 Gin 引擎设置为其Handler,随后将配置对象和 HTTP 服务器实例注入到新创建的 Server 结构体中并返回。
步骤 3:设置 Gin 路由
有时候服务器进程起来不代表服务器可以正常对外提供 API,我就曾经就遇到过这种问题:服务器进程存在,但是访问 API 确实失败的。
因此在启动服务器时,最好加一个健康检查接口。可以在健康检查接口中,检查任何我们觉得会影响服务器健康状态的项目。
在代码清单 10-1 中,通过以下方法调用给 engine 实例添加了一条健康检查 HTTP 路由:
// 注册 /healthz handler.engine.GET("/healthz", func(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"status": "ok"})})
engine 实例提供了 GET、POST、DELETE、PATCH、PUT、OPTIONS、HEAD、Any 方法,来给 engine 实例添加对应的 HTTP 路由。
上述代码添加了一条 HTTP 路由:
- 请求方法:
GET; - 请求路径:
/healthz; - 请求返回:
{"status":"ok"}。
步骤 4:启动 Gin 服务器
在 NewServer 方法中创建了 Server 类型的实例,接下来就可以在 Server 实例的 Run 方法中启动 HTTP 服务器。代码如下:
// Run 运行应用.
func (s *Server) Run() error {// 运行 HTTP 服务器// 打印一条日志,用来提示 HTTP 服务已经起来,方便排障slog.Info("Start to listening the incoming requests on http address", "addr", s.cfg.Addr)if err := s.srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {return err}return nil
}
上述代码,打印了一条日志,日志中输出了 HTTP 服务器的请求端口。将请求端口打印出来,可以用来帮助开发者了解 HTTP 的启动配置。
s.srv.ListenAndServe() 方法用来启动 HTTP 服务器。当该方法返回错误时,报错并退出。这里要注意,上述代码处理了一个特殊的错误情况:http.ErrServerClosed。当我们主动调用 http.Server 的 Shutdown() 或 Close() 方法时,ListenAndServe() 会返回这个特定的错误(http.ErrServerClosed),这表示服务器是被预期地、主动地关闭,而非意外崩溃。因此,这种情况不应被视作异常或错误,不需要额外处理或返回。
编译并运行
执行以下命令编译并运行:
$ ./build.sh
$ _output/fg-apiserver -c configs/fg-apiserver.yaml
打开一个新的 Linux 终端,执行以下命令测试功能是否正常:
$ curl http://127.0.0.1:6666/nonexist # 请求路径不存在时,返回预期错误
{"code":"PageNotFound","message":"Page not found."}
$ curl http://127.0.0.1:6666/healthz # 请求健康检查接口,返回服务器 ok 信息
{"status":"ok"}
附录: cURL 工具介绍
本节课采用 cURL 工具来测试 RESTful API,标准的 Linux 发行版都安装了 cURL 工具。cURL 可以很方便地完成对 REST API 的调用场景,比如:设置 Header,指定 HTTP 请求方法,指定 HTTP 消息体,指定权限认证信息等。
通过 -v 选项也能输出 REST 请求的所有返回信息。cURL 功能很强大,有很多参数,这里列出 REST 测试常用的参数:
-X/--request [GET|POST|PUT|DELETE|…] 指定请求的 HTTP 方法
-H/--header 指定请求的 HTTP Header
-d/--data 指定请求的 HTTP 消息体(Body)
-v/--verbose 输出详细的返回信息
-u/--user 指定账号、密码
-b/--cookie 读取 cookie
相关文章:
10 | 基于 Gin 实现 HTTP 服务器
提示: 所有体系课见专栏:Go 项目开发极速入门实战课;欢迎加入 云原生 AI 实战 星球,12 高质量体系课、20 高质量实战项目助你在 AI 时代建立技术竞争力(聚焦于 Go、云原生、AI Infra);本节课最终…...
PyTorch 深度学习实战(14):Deep Deterministic Policy Gradient (DDPG) 算法
在上一篇文章中,我们介绍了 Proximal Policy Optimization (PPO) 算法,并使用它解决了 CartPole 问题。本文将深入探讨 Deep Deterministic Policy Gradient (DDPG) 算法,这是一种用于连续动作空间的强化学习算法。我们将使用 PyTorch 实现 D…...
Ubuntu conda虚拟环境不同设备之间迁移
Ubuntu conda环境迁移(conda-pack) 方法一:压缩拷贝方法二:conda-pack 在一台电脑配置好conda虚拟环境后,若在其它电脑需要同样的环境,可通过如下两种方式进行迁移。 方法一:压缩拷贝 找到Ubu…...
Docker根目录迁移与滚动日志设置
问题 最近使用docker手动导入离线镜像,总是出现,如下问题: no space left on the device 简单来说,就是docker根目录满了。 解决 查询当前docker info设置位置 使用如下命令,查询docker根目录位置: do…...
【JVM】GC 常见问题
GC 常见问题 哪些情况新生代会进入老年代 新生代 GC 后幸存区(survivor)不够存放存活下来的对象,会通过内存担保机制晋升到老年代。大对象直接进入老年代,因为大对象再新生代之间来会复制会影响 GC 性能。由 -XX:PretenureSizeT…...
「Unity3D」UGUI运行时设置元素的锚点Anchor,维持元素Rect的显示不变,即待在原处
在编辑器中,通过设置Raw edit mode,可以切换两种,元素锚点的改变模式: 一种是锚点单独改变,即:不开启原始模式,保持原样,改变anchoredPosition与sizeDelta。一种是锚点联动显示&…...
Angular由一个bug说起之十四:SCSS @import 警告与解决⽅案
SCSS import 警告与解决⽅案 ⚠ 警告信息 在 SCSS 中,使⽤ import 可能会产⽣以下警告: Deprecation Warning: Sass import rules are deprecated and will be removed in Dart Sass 3.0.0. ? 为什么会有这个警告? Sass 官⽅已经废弃 imp…...
PyTorch系列教程:基于LSTM构建情感分析模型
情感分析是一种强大的自然语言处理(NLP)技术,用于确定文本背后的情绪基调。它常用于理解客户对产品或服务的意见和反馈。本文将介绍如何使用PyTorch和长短期记忆网络(LSTMs)创建一个情感分析管道,LSTMs在处…...
SEO新手基础优化三步法
内容概要 在网站优化的初始阶段,新手常因缺乏系统性认知而陷入技术细节的误区。本文以“三步法”为核心框架,系统梳理从关键词定位到内容布局、再到外链构建的完整优化链路。通过拆解搜索引擎工作原理,重点阐明基础操作中容易被忽视的底层逻…...
Tcp网络通信的基本流程梳理
先来一张经典的流程图 接下介绍一下大概流程,各个函数的参数大家自己去了解加深一下印象 服务端流程 1.创建套接字:使用 socket 函数创建一个套接字,这个套接字后续会被用于监听客户端的连接请求。 需要注意的是,服务端一般有俩…...
PHP函数缺陷详解
无问社区-官网:http://www.wwlib.cn 本期无人投稿,欢迎大家投稿,投稿可获得无问社区AI大模型的使用红包哦! 无问社区:网安文章沉浸式免费看! 无问AI大模型不懂的问题随意问! 全网网安资源智…...
解决 Redis 后台持久化失败的问题:内存不足导致 fork 失败
文章目录 解决 Redis 后台持久化失败的问题:内存不足导致 fork 失败问题背景与成因解决方案修改内核参数 vm.overcommit_memory增加系统内存或 Swap 空间调整 Redis 配置 stop-writes-on-bgsave-error 在 Docker 环境中的注意事项总结 解决 Redis 后台持久化失败的问…...
深度学习GRU模型原理
一、介绍 门控循环单元(Gated Recurrent Unit, GRU) 是一种改进的循环神经网络(RNN),专为解决传统RNN的长期依赖问题(梯度消失/爆炸)而设计。其核心是通过门控机制动态控制信息的流动。与LSTM相…...
网络空间安全(31)安全巡检
一、定义与目的 定义: 安全巡检是指由专业人员或特定部门负责,对各类设施、设备、环境等进行全面或重点检查,及时发现潜在的安全隐患或问题。 目的: 预防事故发生:通过定期的安全巡检,及时发现并解决潜在的…...
基于Python+SQLite实现(Web)验室设备管理系统
实验室设备管理系统 应用背景 为方便实验室进行设备管理,某大学拟开发实验室设备管理系统 来管理所有实验室里的各种设备。系统可实现管理员登录,查看现有的所有设备, 增加设备等功能。 开发环境 Mac OSPyCharm IDEPython3Flaskÿ…...
面试系列|蚂蚁金服技术面【2】
今天继续分享一下蚂蚁金服的 Java 后端开发岗位真实社招面经,复盘面试过程中踩过的坑,整理面试过程中提到的知识点,希望能给正在准备面试的你一些参考和启发,希望对你有帮助,愿你能够获得心仪的 offer ! 第一轮面试完…...
【JavaEE】网络原理之初识
1.❤️❤️前言~🥳🎉🎉🎉 Hello, Hello~ 亲爱的朋友们👋👋,这里是E绵绵呀✍️✍️。 如果你喜欢这篇文章,请别吝啬你的点赞❤️❤️和收藏📖📖。如果你对我的…...
WorkTool 技术解析:企业微信自动化办公的合规实现方案
引言:企业微信生态中的自动化需求 随着企业微信用户规模突破4亿(据腾讯2023年财报),其开放生态催生了自动化办公的技术需求。传统RPA(机器人流程自动化)工具在PC端已广泛应用,但移动端自动化仍…...
从0到1构建AI深度学习视频分析系统--基于YOLO 目标检测的动作序列检查系统:(2)消息队列与消息中间件
文章大纲 原始视频队列Python 内存视频缓存优化方案(4GB 以内)一、核心参数设计二、内存管理实现三、性能优化策略四、内存占用验证五、高级优化技巧六、部署建议检测结果队列YOLO检测结果队列技术方案一、技术选型矩阵二、核心实现代码三、性能优化策略四、可视化方案对比五…...
一文讲通锁标记对象std::adopt_lock盲点
一文讲通锁标记对象std::adopt_lock盲点 1. 核心概念2. 代码详解1. 单个锁2. 多重锁(可以用来预防死锁)3. 条件变量的互斥控制4. 复杂示例: 多生产者-多消费者模型(超纲了, 可不看,哈哈哈哈) 3. 小结 1. 核心概念 在C中, std::adopt_lock是一…...
Vscode工具开发Vue+ts项目时vue文件ts语法报错-红波浪线等
Vscode工具开发Vuets项目时vue文件ts语法报错-红波浪线等 解决方案 问题如题描述,主要原因是开发工具使用的代码检查与项目的中的ts不一致导导致,解决办法,修改 vscode 中, 快捷键:command shift p, 输入ÿ…...
Mac下安装Zed以及Zed对MCP(模型上下文协议)的支持
Zed是当前新流行的一种编辑器,支持MCP(模型上下文协议) Mac下安装Zed比较简单,直接有安装包,在这里: brew install --cask zedMac Monterey下是可以安装上的,亲测有效。 配置 使用CtrlShiftP…...
ROS实践(五)机器人自动导航(robot_navigation)
目录 一、知识点 1. 定位 2. 路径规划 (1)全局路径规划 (2)局部路径规划 3. 避障 二、常用工具和传感器 三、相关功能包 1. move_base(决策规划) 2. amcl(定位) 3. costmap_2d(代价地图) 4. global_planner(全局规划器) 5. local_planner(局部规划器…...
REDIS生产环境配置
REDIS生产环境配置 REDIS生产环境配置docker-compose文件redis.conf文件 REDIS生产环境配置 docker-compose模式部署生产环境 docker-compose文件 d_redis:image: redis:${REDIS_VERSION}container_name: d_redisvolumes:- ${REDIS_1_CONF_FILE}:/etc/redis.conf:ro- ${DATA_…...
【小沐学Web3D】three.js 加载三维模型(React)
文章目录 1、简介1.1 three.js1.2 react.js 2、three.js React结语 1、简介 1.1 three.js Three.js 是一款 webGL(3D绘图标准)引擎,可以运行于所有支持 webGL 的浏览器。Three.js 封装了 webGL 底层的 API ,为我们提供了高级的…...
软考教材重点内容 信息安全工程师 第19章 操作系统安全保护
19.1.1 操作系统安全概念 一般来说,操作系统的安全是指满足安全策略要求,具有相应的安全机制及安全功能,符合特定的安全标准,在一定约束条件下,能够抵御常见的网络安全威胁,保障自身的安全运行及资源安全。…...
【C++设计模式】第二十一篇:模板方法模式(Template Method)
注意:复现代码时,确保 VS2022 使用 C17/20 标准以支持现代特性。 算法骨架的标准化定义 1. 模式定义与用途 核心思想 模板方法模式:在父类中定义算法的骨架,将某些步骤延迟到子类实现,使得子类不改变算法结构即可…...
【机器学习】基于t-SNE的MNIST数据集可视化探索
一、前言 在机器学习和数据科学领域,高维数据的可视化是一个极具挑战但又至关重要的问题。高维数据难以直观地理解和分析,而有效的可视化方法能够帮助我们发现数据中的潜在结构、模式和关系。本文以经典的MNIST手写数字数据集为例,探讨如何利…...
【Pycharm】Pycharm无法复制粘贴,提示系统剪贴板不可用
我也没有用vim的插件,检查了本地和ubutnu上都没有。区别是我是远程到ubutnu的pycharm,我本地直接控制windowes的pycharm是没问题的。现象是可以从外部复制到pycharm反之则不行。 ctl c ctlv 以及右键 都不行 参考:Pycharm无法复制粘贴&…...
基于python+django+vue.js开发的医院门诊管理系统/医疗管理系统源码+运行
功能介绍 平台采用B/S结构,后端采用主流的Python语言进行开发,前端采用主流的Vue.js进行开发。源码 功能包括:医生管理、科室管理、护士管理、住院管理、药品管理、用户管理、日志管理、系统信息模块。 源码地址 https://github.com/geee…...
