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,
})
}
æ´æ°ä¸»åºç¨æä»¶â
æ´æ° main.go æä»¶ï¼æ·»å è·¯ç±åä¸é´ä»¶ï¼
package main
import (
"fmt"
"net/http"
"os"
"time"
"cloudrun-gin/controllers"
"github.com/gin-gonic/gin"
)
func main() {
// 设置 Gin 模å¼
if os.Getenv("GIN_MODE") == "" {
gin.SetMode(gin.ReleaseMode)
}
router := gin.Default()
// æ·»å CORS ä¸é´ä»¶
router.Use(func(c *gin.Context) {
c.Header("Access-Control-Allow-Origin", "*")
c.Header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
c.Header("Access-Control-Allow-Headers", "Content-Type, Authorization")
if c.Request.Method == "OPTIONS" {
c.AbortWithStatus(http.StatusNoContent)
return
}
c.Next()
})
// æ·»å æ¥å¿ä¸é´ä»¶
router.Use(gin.LoggerWithFormatter(func(param gin.LogFormatterParams) string {
return fmt.Sprintf("%s - [%s] \"%s %s %s %d %s \"%s\" %s\"\n",
param.ClientIP,
param.TimeStamp.Format(time.RFC1123),
param.Method,
param.Path,
param.Request.Proto,
param.StatusCode,
param.Latency,
param.Request.UserAgent(),
param.ErrorMessage,
)
}))
// åºç¡è·¯ç±
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",
"timestamp": time.Now().Format(time.RFC3339),
"framework": "Gin",
"go_version": "1.19+",
"gin_version": gin.Version,
})
})
// API è·¯ç±ç»
api := router.Group("/api")
{
users := api.Group("/users")
{
users.GET("", controllers.GetUsers)
users.GET("/:id", controllers.GetUser)
users.POST("", controllers.CreateUser)
}
}
// è·å端å£ï¼æ¯æç¯å¢åé
port := os.Getenv("PORT")
if port == "" {
port = "8080"
}
// å¯å¨æå¡å¨
router.Run(":" + port)
}
ç¬¬ä¸æ¥ï¼æ¬å°æµè¯â
æ´æ°ä¾èµâ
go mod tidy
å¯å¨åºç¨â
go run main.go
æµè¯ API æ¥å£â
# æµè¯å¥åº·æ£æ¥
curl http://localhost:8080/health
# æµè¯é¦é¡µ
curl http://localhost:8080/
# æµè¯ç¨æ·å表
curl http://localhost:8080/api/users
# æµè¯å页
curl "http://localhost:8080/api/users?page=1&limit=2"
# æµè¯è·ååä¸ªç¨æ·
curl http://localhost:8080/api/users/1
# æµè¯åå»ºç¨æ·
curl -X POST http://localhost:8080/api/users \
-H "Content-Type: application/json" \
-d '{"name":"æ°ç¨æ·","email":"newuser@example.com"}'
ç¬¬åæ¥ï¼åå¤é¨ç½²æä»¶â
1. å建å¯å¨èæ¬â
ð¡ æ³¨æï¼
- å¨ windows ä¸å建
scf_bootstrapæä»¶æ¶ï¼ä¼å 使ç¨nano scf_bootstrapæèvim scf_bootstrapå建- å¨ windows ä¸ä½¿ç¨ vscode å建
scf_bootstrapæä»¶æ¶ï¼é¨ç½²å° HTTP äºå½æ°å¯è½ä¼æ¥é:scf_bootstrapæä»¶ä¸åå¨- è¿ä¸ªé误æ¯å ä¸ºèæ¬æä»¶å å«äº Windows æ ¼å¼çå车符ï¼^Mï¼ï¼å¯¼è´ Linux æ æ³æ£ç¡®è¯å«è§£éå¨è·¯å¾ãè¿æ¯ WSL ä¸å¸¸è§çé®é¢
å建 scf_bootstrap æä»¶ï¼æ æ©å±åï¼ï¼
#!/bin/bash
export PORT=9000
export GIN_MODE=release
./main
为å¯å¨èæ¬æ·»å æ§è¡æéï¼
chmod +x scf_bootstrap
2. ç¼è¯åºç¨â
ç¼è¯ Go åºç¨ä¸º Linux äºè¿å¶æä»¶ï¼
# 交åç¼è¯ä¸º Linux 64ä½
GOOS=linux GOARCH=amd64 go build -o main .
3. 项ç®ç»æâ
cloudrun-gin/
âââ controllers/
â âââ user.go
âââ models/
â âââ user.go
âââ main.go
âââ go.mod
âââ go.sum
âââ main # ç¼è¯åçäºè¿å¶æä»¶
âââ scf_bootstrap # ð äºå½æ°å¯å¨èæ¬
ð¡ 说æï¼
scf_bootstrapæ¯ CloudBase äºå½æ°çå¯å¨èæ¬- éè¦å° Go åºç¨ç¼è¯ä¸º Linux äºè¿å¶æä»¶
- 设置
PORT=9000ç¯å¢åéç¡®ä¿åºç¨ç嬿£ç¡®ç«¯å£- 设置
GIN_MODE=releaseä¼åæ§è½
ç¬¬äºæ¥ï¼ é¨ç½²å° CloudBaseâ
éè¿æ§å¶å°é¨ç½²â
- ç»å½ CloudBase æ§å¶å°
- éæ©æ¨çç¯å¢ï¼è¿å ¥ãäºå½æ°ã页é¢
- ç¹å»ãæ°å»ºäºå½æ°ã
- éæ©ãHTTP äºå½æ°ã
- å¡«å彿°åç§°ï¼å¦ï¼
gin-appï¼ - éæ©è¿è¡æ¶ï¼Go 1.xï¼æå ¶ä»æ¯æççæ¬ï¼
- æäº¤æ¹æ³éæ©ï¼æ¬å°ä¸ä¼ 代ç å
- ä¸ä¼ ç¼è¯åçäºè¿å¶æä»¶å
scf_bootstrapæä»¶ - èªå¨å®è£ ä¾èµï¼å ³éï¼Go åºç¨æ 鿤é项ï¼
- ç¹å»ãå建ãæé®çå¾ é¨ç½²å®æ
æå é¨ç½²â
妿éè¦æå¨æå ï¼
# ç¼è¯åºç¨
GOOS=linux GOARCH=amd64 go build -o main .
# å建é¨ç½²å
zip -j gin-app.zip main scf_bootstrap
ç¬¬å æ¥: è®¿é®æ¨çåºç¨â
é¨ç½²æååï¼æ¨å¯ä»¥åèéè¿ HTTP 访é®äºå½æ°è®¾ç½®èªå®ä¹åå访é®HTTP äºå½æ°ã
示ä¾è¯·æ±â
# å¥åº·æ£æ¥
curl https://your-app-url/health
# è·åç¨æ·å表
curl https://your-app-url/api/users
# å页æ¥è¯¢
curl "https://your-app-url/api/users?page=1&limit=2"
# å建æ°ç¨æ·
curl -X POST https://your-app-url/api/users \
-H "Content-Type: application/json" \
-d '{"name":"æµè¯ç¨æ·","email":"test@example.com"}'
常è§é®é¢â
Q: 为ä»ä¹ HTTP äºå½æ°å¿ é¡»ä½¿ç¨ 9000 端å£ï¼â
A: CloudBase HTTP äºå½æ°è¦æ±åºç¨çå¬ 9000 端å£ï¼è¿æ¯å¹³å°çæ åé
ç½®ãåºç¨éè¿ç¯å¢åé PORT=9000 æ¥æ§å¶ç«¯å£ï¼æ¬å°å¼åæ¶é»è®¤ä½¿ç¨ 8080 端å£ã
Q: Go åºç¨å¦ä½è¿è¡äº¤åç¼è¯ï¼â
A: 使ç¨ä»¥ä¸å½ä»¤è¿è¡äº¤åç¼è¯ï¼
GOOS=linux GOARCH=amd64 go build -o main .
Q: å¦ä½ä¼å Go åºç¨çå·å¯å¨æ¶é´ï¼â
A:
- åå°ä¾èµå æ°é
- 使ç¨
gin.ReleaseModeæ¨¡å¼ - é¿å å¨å¯å¨æ¶è¿è¡éå¤çåå§åæä½
- åç设置å åé ç½®
Q: scf_bootstrap æä»¶æä»ä¹ä½ç¨ï¼â
A: scf_bootstrap æ¯äºå½æ°çå¯å¨èæ¬ï¼ç¨äºè®¾ç½®ç¯å¢åéåå¯å¨ç¼è¯åçäºè¿å¶æä»¶ã
ä¸ä¸æ¥â
- äºè§£æ´å¤ HTTP äºå½æ°é ç½®é项
- å¦ä¹ å¦ä½ è¿æ¥ CloudBase æ°æ®åº