代码仓库

gitee本例代码
gitee之前写的

创建项目

先创建目录, 然后在该目录下执行

1
2
3
4
5
go mod init quick-start
# 每次运行前执行, 确保项目依赖关系正确
go mod tidy
# 运行
go run main.go

目录结构

一般web工程采用MVC结构, M就是model, V是view, C是controller

  • Model(模型)
    负责管理应用程序的核心数据和业务逻辑。
    与数据库或其他数据源交互,并处理数据的增删改查操作。
    当数据发生变化时,通知View进行更新。
  • View(视图)
    负责显示用户界面,通常基于Model的数据进行渲染。
    用户可以通过View与应用程序进行交互。
    View监听Model的变化并自动刷新显示。
  • Controller(控制器)
    负责接收用户的输入(例如点击按钮、提交表单等),并协调Model和View之间的交互。
    根据用户的操作调用Model的方法或更新View的状态。
    控制器充当Model和View之间的桥梁。

所以一般的目录结构包含
models/controllers/middleware
其中, models存放的是模型文件, controllers存放的是控制器文件, middleware存放的是中间件文件
而views则一般是单独分离出前端项目来开发

1
2
3
4
5
6
7
8
9
10
11
12
- common/ 或 utils/
- controllers/
- initializers/
- middleware/
- migrate/
- models/
- scripts/
- .env
- go.mod
- go.sum
- main.go
- readme.md

数据库

我们使用gorm框架操作数据库

创建数据库表

gorm支持自动生成数据库表结构, 只需要定义模型结构体, 然后使用gorm的代码来生成就行

先连接到数据库, 为了方便, 我们使用sqlite

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// initializers/loadEnv.go
/*
* @Author Malred
* @Date 2025-06-15 21:24:25
* @Description 连接到数据库, 对外提供数据库实例
*/
package initializers

import (
"log"
"os"

"gorm.io/driver/mysql"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
)

var DB *gorm.DB

func ConnectToDB() {
//ConnectToMysql()
ConnectToSqlite()
}

func ConnectToMysql() {
var err error
dsn := os.Getenv("MYSQL_DB_URL")
DB, err = gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
log.Fatal("Failed to connect to database")
}
}

func ConnectToSqlite() {
var err error
dbPath := os.Getenv("SQLITE_MDB_URL") // 通过环境变量指定 SQLite 数据库文件路径
DB, err = gorm.Open(sqlite.Open(dbPath), &gorm.Config{})
if err != nil {
log.Fatal("Failed to connect to database")
}
}

数据库等配置, 我们使用.env文件来保存

1
2
3
4
5
6
7
8
# web运行端口
PORT=4000
# 随机生成的UUID, 用于生成JWT
SECRET=8d6f7b7d-2f24-4867-ae90-feb4fc646693
# MYSQL数据库连接地址
MYSQL_DB_URL=root:123456@tcp(127.0.0.1:3306)/quick-starter?charset=utf8mb4&parseTime=True&loc=Local
# SQLITE数据库连接地址
SQLITE_MDB_URL=./dev.db

go语言加载.env文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// initializers/loadEnv.go
/*
* @Author Malred
* @Date 2025-06-15 21:24:15
* @Description 加载.env文件中的环境变量
*/
package initializers

import (
"github.com/joho/godotenv"
"log"
)

func LoadEnvVariables() {
// 加载.env, 里面设置了port, gin会读取并设置端口号
err := godotenv.Load()
if err != nil {
log.Fatal("Error loading .env file")
}
}

声明对应数据库表的模型model

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// models/user.go
/*
* @Author Malred
* @Date 2025-06-15 21:35:54
* @Description
*/
package models

type User struct {
ID uint `gorm:"primarykey"`
Username string
Password string
Email string
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// models/post.go
/*
* @Author Malred
* @Date 2025-06-15 21:36:06
* @Description
*/
package models

import "gorm.io/gorm"

type Post struct {
gorm.Model
Title string
Body string
}

用代码生成数据库表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// migrate/migrate.go
/*
* @Author Malred
* @Date 2025-06-15 21:22:42
* @Description 使用gorm框架的方法, 创建数据库表
*/
package main

import (
"quick-start/initializers"
"quick-start/models"
)

func init() {
initializers.LoadEnvVariables()
initializers.ConnectToDB()
}

func main() {
// 创建数据库
initializers.DB.AutoMigrate(&models.User{})
initializers.DB.AutoMigrate(&models.Post{})
}

用户信息表

增删改查

实现对用户信息的基本操作:增加、删除、修改和查询。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
// user_test.go
/*
* @Author Malred
* @Date 2025-06-15 21:43:05
* @Description
*/
package go_quick_starter

import (
"quick-start/initializers"
"quick-start/models"
"testing"
)

func CreateUser(user *models.User) error {
result := initializers.DB.Create(user)
return result.Error
}
func GetUserByID(id uint) (*models.User, error) {
var user models.User
result := initializers.DB.First(&user, id)
return &user, result.Error
}
func GetAllUsers() ([]models.User, error) {
var users []models.User
result := initializers.DB.Find(&users)
return users, result.Error
}
func UpdateUser(user *models.User) error {
result := initializers.DB.Save(user)
return result.Error
}
func DeleteUser(id uint) error {
result := initializers.DB.Delete(&models.User{}, id)
return result.Error
}

// 保存新增的用户的ID
var ID int = 1

func TestCreateUser(t *testing.T) {
initializers.LoadEnvVariables()
initializers.ConnectToDB()

user := &models.User{
Email: "create@example.com",
Password: "password123",
Username: "createuser",
}

err := CreateUser(user)
if err != nil || user.ID == 0 {
t.Errorf("Failed to create user: %v", err)
}
ID = int(user.ID)
}

func TestGetUserByID(t *testing.T) {
initializers.LoadEnvVariables()
initializers.ConnectToDB()

retrievedUser, err := GetUserByID(uint(ID))
if err != nil || retrievedUser.ID == 0 {
t.Errorf("Failed to retrieve user: %v", err)
}
}

func TestGetAllUsers(t *testing.T) {
initializers.LoadEnvVariables()
initializers.ConnectToDB()

// 插入两个用户
user1 := &models.User{Email: "all1@example.com", Password: "pass", Username: "user1"}
user2 := &models.User{Email: "all2@example.com", Password: "pass", Username: "user2"}
initializers.DB.Create(user1)
initializers.DB.Create(user2)

users, err := GetAllUsers()
if err != nil || len(users) < 2 {
t.Errorf("Failed to get all users: %v", err)
}
}

func TestUpdateUser(t *testing.T) {
initializers.LoadEnvVariables()
initializers.ConnectToDB()

// 更新用户
user := &models.User{
ID: uint(ID),
Email: "update@example.com",
Password: "password123",
Username: "oldname",
}

err := UpdateUser(user)
if err != nil {
t.Errorf("Failed to update user: %v", err)
}
}

func TestDeleteUser(t *testing.T) {
initializers.LoadEnvVariables()
initializers.ConnectToDB()

// 删除用户
err := DeleteUser(uint(ID))
if err != nil {
t.Errorf("Failed to delete user: %v", err)
}
}

密码加密

为了保证用户信息安全,需要对用户的密码进行加密处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import (
"fmt"
"golang.org/x/crypto/bcrypt"
"os"
"quick-start/initializers"
"quick-start/models"
"testing"
"time"
)

func TestBcryptPasswordEncode(t *testing.T) {
user := &models.User{
Email: "create@example.com",
Password: "password123",
Username: "createuser",
}

// 密码加盐(加密)
hash, err := bcrypt.GenerateFromPassword([]byte(user.Password), 10)
if err != nil {
t.Errorf("Failed to hash password")
}
fmt.Println(hash)
fmt.Println(string(hash))
}

创建JWT令牌

JWT(JSON Web Token)是一种开放标准,用于在网络应用环境间安全地传递声明。创建JWT令牌是为了实现用户身份验证。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import (
"fmt"
"github.com/golang-jwt/jwt/v4"
"golang.org/x/crypto/bcrypt"
"os"
"quick-start/initializers"
"quick-start/models"
"testing"
"time"
)

func TestJWT(t *testing.T) {
user := &models.User{
Email: "create@example.com",
Password: "password123",
Username: "createuser",
}

// 密码加盐(加密)
hash, err := bcrypt.GenerateFromPassword([]byte(user.Password), 10)
if err != nil {
t.Errorf("Failed to hash password")
}
fmt.Println(hash)
fmt.Println(string(hash))

// 校验密码
err = bcrypt.CompareHashAndPassword([]byte(hash), []byte(user.Password))
if err != nil {
t.Errorf("Invalid password")
}

// 生成jwt令牌(传输协议用https,加密传输,防止jwt泄露)
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
"sub": user.ID,
// 过期时间
"exp": time.Now().Add(time.Hour * 24 * 30).Unix(),
})

// 传入密钥,加密
tokenStr, err := token.SignedString([]byte(os.Getenv("SECRET")))
if err != nil {
t.Errorf("Failed to generate token")
}
fmt.Println(tokenStr)
}

进行测试

帖子信息表

增删改查

实现对帖子信息的基本操作:增加、删除、修改和查询。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
// /post_test.go
package go_quick_starter

import (
"quick-start/initializers"
"quick-start/models"
"testing"
)

func CreatePost(post *models.Post) error {
result := initializers.DB.Create(post)
return result.Error
}
func GetPostByID(id uint) (*models.Post, error) {
var post models.Post
result := initializers.DB.First(&post, id)
return &post, result.Error
}
func GetAllPosts() ([]models.Post, error) {
var posts []models.Post
result := initializers.DB.Find(&posts)
return posts, result.Error
}
func UpdatePost(post *models.Post) error {
result := initializers.DB.Save(post)
return result.Error
}
func DeletePost(id uint) error {
result := initializers.DB.Delete(&models.Post{}, id)
return result.Error
}

func TestCreatePost(t *testing.T) {
initializers.LoadEnvVariables()
initializers.ConnectToDB()

post := &models.Post{
Title: "test",
Body: "test body",
}

err := CreatePost(post)
if err != nil || post.ID == 0 {
t.Errorf("Failed to create user: %v", err)
}
ID = int(post.ID)
}

func TestGetPostByID(t *testing.T) {
initializers.LoadEnvVariables()
initializers.ConnectToDB()

retrievedPost, err := GetPostByID(uint(ID))
if err != nil || retrievedPost.ID == 0 {
t.Errorf("Failed to retrieve user: %v", err)
}
}

func TestGetAllPosts(t *testing.T) {
initializers.LoadEnvVariables()
initializers.ConnectToDB()

// 插入两个用户
post1 := &models.Post{
Title: "test",
Body: "test body",
}
post2 := &models.Post{
Title: "test",
Body: "test body",
}
initializers.DB.Create(post1)
initializers.DB.Create(post2)

users, err := GetAllPosts()
if err != nil || len(users) < 2 {
t.Errorf("Failed to get all users: %v", err)
}
}

func TestUpdatePost(t *testing.T) {
initializers.LoadEnvVariables()
initializers.ConnectToDB()

// 更新用户
post := &models.Post{
Title: "test",
Body: "test body",
}

err := UpdatePost(post)
if err != nil {
t.Errorf("Failed to update user: %v", err)
}
}

func TestDeletePost(t *testing.T) {
initializers.LoadEnvVariables()
initializers.ConnectToDB()

// 删除用户
err := DeletePost(uint(ID))
if err != nil {
t.Errorf("Failed to delete user: %v", err)
}
}

网络接口

定义路由

restful风格API:

HTTP 方法|操作类型|示例
GET|查询资源|获取用户列表 /api/users
POST|创建资源|创建新用户 /api/users
PUT|更新资源|更新指定用户 /api/users/{id}
DELETE|删除资源|删除指定用户 /api/users/{id}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// /main.go
/*
* @Author Malred
* @Date 2025-06-16 08:00:23
* @Description
*/
package main

import (
"github.com/gin-gonic/gin"
"quick-start/controllers"
"quick-start/initializers"
"quick-start/middleware"
)

// 启动时自动调用
func init() {
initializers.LoadEnvVariables()
initializers.ConnectToDB()
}

func main() {
r := gin.Default()

r.Use(middleware.Cors())
{
r.GET("posts", controllers.PostsIndex)
r.GET("posts/:id", controllers.PostsShow)
r.GET("posts/page", controllers.PostsPage)
r.POST("posts", middleware.RequireAuthHeader, controllers.PostsCreate)
r.PATCH("posts/:id", middleware.RequireAuthHeader, controllers.PostsUpdate)
r.DELETE("posts/:id", middleware.RequireAuthHeader, controllers.PostsDelete)
}
{
r.GET("auth/profile", middleware.RequireAuthHeader, controllers.Validate)
r.POST("users", controllers.Register)
r.POST("auth/login", controllers.Login)
}
r.Run()
}

登陆注册

实现用户的登录和注册功能,包括身份验证和账户创建。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
// controllers/user.go
/*
* @Author Malred
* @Date 2025-06-16 08:00:44
* @Description
*/
package controllers

import (
"net/http"
"os"
"quick-start/initializers"
"quick-start/models"
"time"

"github.com/gin-gonic/gin"
"github.com/golang-jwt/jwt/v4"
"golang.org/x/crypto/bcrypt"
)

// 注册
func Register(c *gin.Context) {
var body struct {
Username string `json:"username" validate:"min=5"`
Password string `json:"password" validate:"min=8"`
RetypedPassword string `json:"retypedPassword" validate:"min=8,eqfield=Password"`
Email string `json:"email" validate:"email"`
}

// 将json数据绑定到结构体
c.Bind(&body)

// 校验
err := validate.Struct(body)
if err != nil {
c.JSON(400, gin.H{
"error": err.Error(),
})
return
}

var user models.User
initializers.DB.
Where("email = ?", body.Email).
First(&user)

// 已存在(其实username也是唯一的,设计在表里了)
if user != (models.User{}) {
c.JSON(500, gin.H{
"error": "the email is already exist!",
})
return
}

// hash the password
hash, err := bcrypt.GenerateFromPassword([]byte(body.Password), 10)
if err != nil {
c.JSON(500, gin.H{
"error": "failed to hash password",
})
return
}

user = models.User{
Username: body.Username,
Password: string(hash),
Email: body.Email,
}

result := initializers.DB.
Create(&user)

if result.Error != nil {
c.JSON(500, gin.H{
"error": "failed to create user",
})
return
}

c.JSON(200, gin.H{
"user": user,
})
}

// 登录
func Login(c *gin.Context) {
var body struct {
Username string `json:"username"`
Password string `json:"password"`
}

if err := c.Bind(&body); err != nil {
c.JSON(400, gin.H{
"error": "failed to bind the body!",
})
return
}

var user models.User
initializers.DB.
Where("username = ?", body.Username).
Find(&user)

if user == (models.User{}) {
c.JSON(500, gin.H{
"error": "con't find the user!",
})
return
}

// 校验密码
err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(body.Password))
if err != nil {
c.JSON(400, gin.H{
"error": "failed to hash password",
})
return
}
// 生成jwt令牌(传输协议用https,加密传输,防止jwt泄露)
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
"sub": user.ID,
// 过期时间
"exp": time.Now().Add(time.Hour * 24 * 30).Unix(),
})
// 传入密钥,加密
tokenStr, err := token.SignedString([]byte(os.Getenv("SECRET")))
if err != nil {
c.JSON(400, gin.H{
"error": "Failed to create token",
})
return
}
// 设置cookie
c.SetSameSite(http.SameSiteLaxMode)
c.SetCookie("Authorization", tokenStr, 3600*24*30, "", "", false, true)
c.JSON(200, gin.H{
"token": tokenStr,
"userId": user.ID,
})
}

// 校验,返回用户信息
func Validate(c *gin.Context) {
id, _ := c.Get("id")
uname, _ := c.Get("username")
email, _ := c.Get("email")
c.JSON(200, gin.H{
"id": id,
"username": uname,
"email": email,
})
}

帖子信息接口

提供获取、发布、更新和删除帖子信息的 API 接口。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
// controllers/post.go
/*
* @Author Malred
* @Date 2025-06-16 08:00:47
* @Description
*/
package controllers

import (
"quick-start/initializers"
"quick-start/models"
"strconv"

"github.com/gin-gonic/gin"
"github.com/go-playground/validator/v10"
)

var validate *validator.Validate

func init() {
validate = validator.New()
}

// 添加
func PostsCreate(c *gin.Context) {
// 获取json数据
var body struct {
Body string `json:"body" validate:"min=6,max=255"`
Title string `json:"title" validate:"min=3,max=20"`
}
// 将json数据绑定到结构体
c.Bind(&body)

// 校验
err := validate.Struct(body)
if err != nil {
c.JSON(400, gin.H{
"error": err.Error(),
})
return
}

post := models.Post{
Title: body.Title,
Body: body.Body,
}

// 创建
result := initializers.DB.Create(&post)
if result.Error != nil {
c.Status(400)
return
}

c.JSON(200, gin.H{
"post": post,
})
}

// 查询所有
func PostsIndex(c *gin.Context) {
var posts []models.Post
initializers.DB.Find(&posts)

c.JSON(200, gin.H{
"posts": posts,
})
}

// 分页查询
func PostsPage(c *gin.Context) {
limitStr := c.Query("limit")
curPageStr := c.Query("currentPage")

limit, err := strconv.Atoi(limitStr)
if err != nil {
c.Status(500)
return
}
curPage, err := strconv.Atoi(curPageStr)
if err != nil {
c.Status(500)
return
}

var posts []models.Post
initializers.DB.
Scopes(models.Paginate(curPage, limit)).
Find(&posts)

c.JSON(200, gin.H{
"posts": posts,
})
}

// 根据id查询
func PostsShow(c *gin.Context) {
id := c.Param("id")

var post models.Post
initializers.DB.First(&post, id)

c.JSON(200, gin.H{
"post": post,
})
}

// 修改
func PostsUpdate(c *gin.Context) {
id := c.Param("id")

var body struct {
Body string `json:"body" validate:"min=6,max=255"`
Title string `json:"title" validate:"min=3,max=20"`
}
// 将json数据绑定到结构体
c.Bind(&body)

// 校验
err := validate.Struct(body)
if err != nil {
c.JSON(400, gin.H{
"error": err.Error(),
})
return
}

var post models.Post
initializers.DB.First(&post, id)

initializers.DB.Model(&post).Updates(models.Post{
Title: body.Title,
Body: body.Body,
})

c.JSON(200, gin.H{
"post": post,
})
}

// 删除
func PostsDelete(c *gin.Context) {
id := c.Param("id")

initializers.DB.Delete(&models.Post{}, id)

c.Status(200)
}

鉴权和跨域中间件

鉴权中间件用于验证用户身份,确保只有授权用户才能访问特定资源。
跨域中间件用于解决跨域请求问题,允许来自不同域的请求访问服务器资源。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
// middleware/auth.go
/*
* @Author Malred
* @Date 2025-06-16 08:01:36
* @Description
*/
package middleware

import (
"fmt"
"net/http"
"os"
"quick-start/initializers"
"quick-start/models"
"time"

"github.com/gin-gonic/gin"
"github.com/golang-jwt/jwt/v4"
)

// 解决跨域问题
func RequireAuthHeader(c *gin.Context) {
// 获取token
tokenStr := c.Request.Header.Get("Authorization")
fmt.Println(tokenStr[:7])
if tokenStr[:6] != "Bearer" {
c.AbortWithStatus(http.StatusUnauthorized)
}
// 验证token
token, err := jwt.Parse(tokenStr[7:], func(token *jwt.Token) (interface{}, error) {
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
}
return []byte(os.Getenv("SECRET")), nil
})
if err != nil {
fmt.Println(token)
c.AbortWithStatus(http.StatusUnauthorized)
}
if cliams, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
// 过期
if float64(time.Now().Unix()) > cliams["exp"].(float64) {
c.AbortWithStatus(http.StatusUnauthorized)
}
// 根据jwt携带消息(userId)查询数据库
var user models.User
initializers.DB.First(&user, cliams["sub"])
if user.ID == 0 {
c.AbortWithStatus(http.StatusUnauthorized)
}
// c.Set("user", user)
c.Set("id", user.ID)
c.Set("username", user.Username)
c.Set("email", user.Email)
c.Next()
} else {
c.AbortWithStatus(http.StatusUnauthorized)
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// middleware/cors.go
/*
* @Author Malred
* @Date 2025-06-16 08:01:40
* @Description
*/
package middleware

import (
"net/http"

"github.com/gin-gonic/gin"
)

// 解决跨域问题
func Cors() gin.HandlerFunc {
return func(c *gin.Context) {
method := c.Request.Method
origin := c.Request.Header.Get("Origin")
c.Header("Access-Control-Allow-Origin", origin)
// c.Header("Access-Control-Allow-Origin", "*")
c.Header("Access-Control-Allow-Headers", "*")
c.Header("Access-Control-Allow-Methods", "*")
c.Header("Access-Control-Expose-Headers", "Content-Length,Access-Control-Allow-Origin,Access-Control-Allow-Headers,Content-Type")
c.Header("Access-Control-Max-Age", "3600")
c.Header("Access-Control-Allow-Credentials", "true")
//放行索引options
if method == "OPTIONS" {
c.AbortWithStatus(http.StatusNoContent)
}
//处理请求
c.Next()
}
}

使用APIfox进行测试

APIfox是一个接口测试工具
apifox
本案例的接口我已经共享了:
接口文档

目前较成熟的二开框架

暂时不了解, 可以看看别人的回答
link

社群

你可以在这些平台联系我:


本站总访问量