Code Repository

Gitee Example Code
Previous Gitee Code

Creating the Project

First, create a directory and then execute the following commands in that directory:

1
2
3
4
5
go mod init quick-start
# Run before each execution to ensure correct project dependencies
go mod tidy
# Run the project
go run main.go

Directory Structure

A typical web application follows the MVC structure, where M stands for Model, V for View, and C for Controller.

  • Model: Manages the core data and business logic of the application. It interacts with databases or other data
    sources and handles CRUD operations. It notifies the View when data changes.
  • View: Responsible for displaying the user interface, usually rendering based on Model data. Users can interact
    with the application through the View. The View listens for changes in the Model and refreshes automatically.
  • Controller: Handles user inputs (e.g., button clicks, form submissions) and coordinates interactions between Model
    and View. It calls Model methods or updates View states based on user actions. The Controller acts as a bridge between
    Model and View.

Thus, the general directory structure includes:
models/controllers/middleware
Where models contain model files, controllers contain controller files, and middleware contains middleware files. The
views are typically developed separately as a front-end project.

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

Database

We use the GORM framework to interact with the database.

Creating Database Tables

GORM supports automatic generation of database table structures. Simply define the model struct and use GORM’s code to
generate it.

First, connect to the database. For convenience, we use 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 Connect to the database and provide a DB instance externally
*/
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") // Specify SQLite database file path via environment variable
DB, err = gorm.Open(sqlite.Open(dbPath), &gorm.Config{})
if err != nil {
log.Fatal("Failed to connect to database")
}
}

Configurations such as database settings are stored in a .env file.

1
2
3
4
5
6
7
8
# Web server port
PORT=4000
# Randomly generated UUID for JWT generation
SECRET=8d6f7b7d-2f24-4867-ae90-feb4fc646693
# MYSQL database connection URL
MYSQL_DB_URL=root:123456@tcp(127.0.0.1:3306)/quick-starter?charset=utf8mb4&parseTime=True&loc=Local
# SQLITE database connection URL
SQLITE_MDB_URL=./dev.db

Loading the .env file in Go:

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 Load environment variables from .env file
*/
package initializers

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

func LoadEnvVariables() {
// Load .env, which sets port, Gin reads and sets port number
err := godotenv.Load()
if err != nil {
log.Fatal("Error loading .env file")
}
}

Declare the model corresponding to the database table:

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
}

Generate the database tables with code:

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 Create database tables using GORM framework methods
*/
package main

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

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

func main() {
// Create database tables
initializers.DB.AutoMigrate(&models.User{})
initializers.DB.AutoMigrate(&models.Post{})
}

User Information Table

Create, Read, Update, Delete (CRUD)

Implement basic operations on user information: create, delete, update, and query.

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
}

// Save the ID of the newly added user
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()

// Insert two users
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()

// Update user
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()

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

Password Encryption

To ensure user information security, it is necessary to encrypt the user’s password.

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",
}

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

Create JWT Token

JWT (JSON Web Token) is an open standard used for securely transmitting information between parties in a network
application environment. Creating a JWT token is to achieve user authentication.

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",
}

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

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

// Generate JWT token (use HTTPS for transmission protocol, encrypted transmission, prevent JWT leakage)
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
"sub": user.ID,
// Expiration time
"exp": time.Now().Add(time.Hour * 24 * 30).Unix(),
})

// Pass in the secret key, encrypt it
tokenStr, err := token.SignedString([]byte(os.Getenv("SECRET")))
if err != nil {
t.Errorf("Failed to generate token")
}
fmt.Println(tokenStr)
}

Conduct Tests

Post Information Table

Create, Read, Update, Delete (CRUD)

Implement basic operations on post information: create, delete, update, and query.

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()

// Insert two posts
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() // This should be `posts` instead of `users` to match the function name and context.
if err != nil || len(users) < 2 { // This should be `posts` instead of `users` to match the function name and context.
t.Errorf("Failed to get all users: %v", err) // This should be `posts` instead of `users` to match the function name and context.
}
}

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

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

err := UpdatePost(post)
if err != nil {
t.Errorf("Failed to update user: %v", err) // This should be `post` instead of `user` to match the function name and context.
}
}

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

// Delete post
err := DeletePost(uint(ID)) // This should be `post` instead of `user` to match the function name and context.
if err != nil {
t.Errorf("Failed to delete user: %v", err) // This should be `post` instead of `user` to match the function name and context.
}
}

Network Interface

Define Routes

RESTful style API:

HTTP Method Operation Type Example
GET Query Resource Get user list /api/users
POST Create Resource Create new user /api/users
PUT Update Resource Update specified user /api/users/{id}
DELETE Delete Resource Delete specified user /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"
)

// Automatically called at startup
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()
}

Login and Registration

Implement user login and registration functions, including authentication and account creation.

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"
)

// Register
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"`
}

// Bind JSON data to the struct
c.Bind(&body)

// Validation
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)

// Already exists (actually, username is also unique, designed in the table)
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,
})
}

// Login
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
}

// Verify password
err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(body.Password))
if err != nil {
c.JSON(400, gin.H{
"error": "failed to hash password",
})
return
}
// Generate JWT token (use HTTPS for transmission protocol, encrypted transmission, prevent JWT leakage)
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
"sub": user.ID,
// Expiration time
"exp": time.Now().Add(time.Hour * 24 * 30).Unix(),
})
// Pass in the secret key, encrypt it
tokenStr, err := token.SignedString([]byte(os.Getenv("SECRET")))
if err != nil {
c.JSON(400, gin.H{
"error": "Failed to create token",
})
return
}
// Set cookie
c.SetSameSite(http.SameSiteLaxMode)
c.SetCookie("Authorization", tokenStr, 3600*24*30, "", "", false, true)
c.JSON(200, gin.H{
"token": tokenStr,
"userId": user.ID,
})
}

// Validate, return user information
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,
})
}

Post Information Interfaces

Provide API interfaces for getting, posting, updating, and deleting post information.

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()
}

// Add Post
func PostsCreate(c *gin.Context) {
// Get JSON data
var body struct {
Body string `json:"body" validate:"min=6,max=255"`
Title string `json:"title" validate:"min=3,max=20"`
}
// Bind JSON data to the struct
c.Bind(&body)

// Validation
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,
}

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

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

// Get All Posts
func PostsIndex(c *gin.Context) {
var posts []models.Post
initializers.DB.Find(&posts)

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

// Paginate 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,
})
}

// Get Post by 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,
})
}

// Update Post by ID
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"`
}
// Bind JSON data to the struct
c.Bind(&body)

// Validation
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,
})
}

// Delete Post by ID
func PostsDelete(c *gin.Context) {
id := c.Param("id")

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

c.Status(200)
}

Authentication and CORS Middleware

The authentication middleware is used to verify user identity, ensuring that only authorized users can access specific
resources.
The CORS middleware is used to resolve cross-origin request issues, allowing requests from different domains to access
server resources.

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"
)

// Solve cross-origin problems
func RequireAuthHeader(c *gin.Context) {
// Get token
tokenStr := c.Request.Header.Get("Authorization")
fmt.Println(tokenStr[:7])
if tokenStr[:6] != "Bearer" {
c.AbortWithStatus(http.StatusUnauthorized)
}
// Validate 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 claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
// Expired
if float64(time.Now().Unix()) > claims["exp"].(float64) {
c.AbortWithStatus(http.StatusUnauthorized)
}
// Query the database based on the JWT message (userId)
var user models.User
initializers.DB.First(&user, claims["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"
)

// Solve cross-origin problems
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")
// Allow preflight options requests
if method == "OPTIONS" {
c.AbortWithStatus(http.StatusNoContent)
}
// Process request
c.Next()
}
}

Testing with APIfox

APIfox is an interface testing tool apifox. The interface for this case has been
shared: Interface Documentation.

Currently Mature Secondary Development Frameworks

Not familiar with them at the moment, you might want to check other people’s
answers link.

Community

You can contact me on these platforms:


本站总访问量