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

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 服务器分为以下几步:

  1. 配置 REST 服务器(配置监听端口);
  2. 创建 Gin 引擎;
  3. 设置 Gin 路由;
  4. 启动 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 实例提供了 GETPOSTDELETEPATCHPUTOPTIONSHEADAny 方法,来给 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.ServerShutdown()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

http://www.mrgr.cn/news/94175.html

相关文章:

  • vue 仿deepseek前端开发一个对话界面
  • 如何搭建一个适配微信小程序,h5,app的uni-app项目
  • Go Ebiten小游戏开发:俄罗斯方块
  • halcon机器人视觉(四)calibrate_hand_eye_stationary_3d_sensor
  • JAVA 基础语法备忘录 -
  • 01 | Go 项目开发极速入门课介绍
  • 如何搭建一个适配微信小程序,h5,app的工程
  • VSCode集成C语言开发环境
  • 要登录的设备ip未知时的处理方法
  • 17 | 实现简洁架构的 Biz 层
  • 【大模型】WPS 接入 DeepSeek-R1详解,打造全能AI办公助手
  • 编程助手学Python--Deepseek对OpenAI的Python库调用GPT-4模型生成对话回复理解
  • Future<V>接口 和 CompletableFuture<T>类 介绍
  • BLDC直流无刷电机转速电流双闭环调速MATLAB仿真
  • 21 | 全面测试项目功能
  • 12 | 给应用添加优雅关停功能
  • 完整项目案例:基于Django的毕业设计选题管理系统(包含源码结构、核心代码及设计文档框架)
  • 【Linux】在VMWare中安装Ubuntu操作系统(2025最新_Ubuntu 24.04.2)#VMware安装Ubuntu实战分享#
  • Node-RED基础1
  • 【Godot4.3】RenderingServer总结