Gin
Gin 是一个用 Go 语言编写的 HTTP Web 框架。它具有类似 Martini 的 API,但性能比 Martini 快 40 倍。Gin 使用了自定义版本的 HttpRouter,因此它不仅提供了极快的路由,还提供了中间件支持。
本指南介绍如何在 CloudBase HTTP 云函数上部署 Gin 应用程序。
示例源码请参考: cloudrun-gin
前置条件
在开始之前,请确保您已经:
- 安装了 Go 1.23 或更高版本
- 拥有腾讯云账号并创建了云开发环境
- 了解基本的 Go 语言和 Gin 框架开发知识
第一步:创建 Gin 应用
💡 提示:如果您已经有一个 Gin 应用,可以跳过此步骤。
创建项目目录
mkdir cloudrun-gin
cd cloudrun-gin
初始化 Go 模块
go mod init cloudrun-gin
go get -u github.com/gin-gonic/gin
创建主应用文件
在 cloudrun-gin 目录下创建 main.go 文件:
package main
import (
"net/http"
"os"
"github.com/gin-gonic/gin"
)
func main() {
// 设置 Gin 模式
if os.Getenv("GIN_MODE") == "" {
gin.SetMode(gin.ReleaseMode)
}
router := gin.Default()
// 基础路由
router.GET("/", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"message": "欢迎使用 Gin CloudBase 应用!",
"status": "running",
})
})
// 健康检查
router.GET("/health", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"status": "healthy",
"framework": "Gin",
"go_version": "1.19+",
"gin_version": gin.Version,
})
})
// 获取端口,支持环境变量
port := os.Getenv("PORT")
if port == "" {
port = "8080"
}
// 启动服务器
router.Run(":" + port)
}
本地测试应用
启动应用:
go run main.go
打开浏览器访问 http://localhost:8080,您应该能看到 JSON 响应。
第二步:添加 API 路由
让我们创建一个 RESTful API 来演示 Gin 的功能。
创建用户模型
在项目根目录创建 models 目录,并创建 user.go 文件:
package models
type User struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
}
type ApiResponse struct {
Success bool `json:"success"`
Message string `json:"message"`
Data interface{} `json:"data,omitempty"`
}
创建用户控制器
在项目根目录创建 controllers 目录,并创建 user.go 文件:
package controllers
import (
"net/http"
"strconv"
"sync"
"cloudrun-gin/models"
"github.com/gin-gonic/gin"
)
var (
users []models.User
usersMu sync.RWMutex
nextID = 1
)
func init() {
// 初始化测试数据
users = []models.User{
{ID: 1, Name: "张三", Email: "zhangsan@example.com"},
{ID: 2, Name: "李四", Email: "lisi@example.com"},
{ID: 3, Name: "王五", Email: "wangwu@example.com"},
}
nextID = 4
}
// GetUsers 获取用户列表
func GetUsers(c *gin.Context) {
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
limit, _ := strconv.Atoi(c.DefaultQuery("limit", "10"))
usersMu.RLock()
defer usersMu.RUnlock()
startIndex := (page - 1) * limit
endIndex := startIndex + limit
if startIndex >= len(users) {
c.JSON(http.StatusOK, models.ApiResponse{
Success: true,
Message: "获取成功",
Data: []models.User{},
})
return
}
if endIndex > len(users) {
endIndex = len(users)
}
paginatedUsers := users[startIndex:endIndex]
c.JSON(http.StatusOK, models.ApiResponse{
Success: true,
Message: "获取成功",
Data: gin.H{
"total": len(users),
"page": page,
"limit": limit,
"items": paginatedUsers,
},
})
}
// GetUser 根据ID获取用户
func GetUser(c *gin.Context) {
id, err := strconv.Atoi(c.Param("id"))
if err != nil {
c.JSON(http.StatusBadRequest, models.ApiResponse{
Success: false,
Message: "无效的用户ID",
})
return
}
usersMu.RLock()
defer usersMu.RUnlock()
for _, user := range users {
if user.ID == id {
c.JSON(http.StatusOK, models.ApiResponse{
Success: true,
Message: "获取成功",
Data: user,
})
return
}
}
c.JSON(http.StatusNotFound, models.ApiResponse{
Success: false,
Message: "用户不存在",
})
}
// CreateUser 创建用户
func CreateUser(c *gin.Context) {
var newUser models.User
if err := c.ShouldBindJSON(&newUser); err != nil {
c.JSON(http.StatusBadRequest, models.ApiResponse{
Success: false,
Message: "请求参数错误: " + err.Error(),
})
return
}
if newUser.Name == "" || newUser.Email == "" {
c.JSON(http.StatusBadRequest, models.ApiResponse{
Success: false,
Message: "姓名和邮箱不能为空",
})
return
}
usersMu.Lock()
newUser.ID = nextID
nextID++
users = append(users, newUser)
usersMu.Unlock()
c.JSON(http.StatusCreated, models.ApiResponse{
Success: true,
Message: "创建成功",
Data: newUser,
})
}