Go Web 开发流程

Go 语言在 Web 后端开发领域越来越受欢迎,原因是:简单、高并发、性能强、部署方便。本文将系统总结 Go Web 开发的完整流程,涵盖从项目初始化到前后端交互以及数据库层设计的全流程。

一、Go Web 项目整体架构

采用典型的 MVC + 分层开发

复制代码
project
│-- main.go           // 程序入口
│
├── router/           // 路由注册
├── controller/       // 控制器层(HTTP 处理、参数解析、响应)
├── service/          // 业务逻辑层
├── dao/              // 数据访问层(数据库操作)
├── model/            // 数据模型定义(结构体的定义)
├── config/           // 配置文件(数据库配置等)
└── views/            // HTML 模板(如果使用 SSR)

二、开发流程概览

接收请求 → 路由 → Controller → Service → DAO → DB

返回结果

三、RESTful 接口设计

什么是 RESTful 架构

(1)每一个 URI 代表一种资源;

URI(URL)不是用来描述动作,而是用来定位资源对象。

(2)客户端和服务器之间,传递这种资源的某种表现层;

客户端与服务器不直接传递 "资源本身",而是传递 "资源的表现层"

资源是抽象的 "数据本身",不依赖任何展示形式。

表现层(Representation):资源的 "具体展示形式",是资源在网络中传输的 "载体"(本质是数据的序列化格式)。常见的有JSON ,XML,HTML。

(3)客户端通过四个 HTTP 动词,对服务器端资源进行操作,实现 "表现层状态转化"。

操作 方法 URL 示例 描述
查询用户 GET /user/123 查询 ID=123 用户
新增用户 POST /adduser/123 创建用户
修改用户 PUT /moduser/123 更新用户信息
删除用户 DELETE /deluser/123 删除用户

REST 的核心是:

  • URL 表示资源,而不是动作。 也就是说URL中并不包含用户的动作。
  • 资源通过 URI 唯一标识,客户端使用 HTTP 方法对资源进行操作,并在资源表现层之间转换状态。

非RESTful风格

Go 复制代码
package router

import (
	"Web/controller"
	"net/http"
)

func InitRouter() {
	http.HandleFunc("/user/get", controller.GetUser)
	http.HandleFunc("/user/create", controller.CreateUser)
	http.HandleFunc("/user/update", controller.UpdateUser)
	http.HandleFunc("/user/delete", controller.DeleteUser)
}

RESTful风格

用gin框架来实现RESTful风格
Go 复制代码
package router

import (
	"Web/controller"
	"github.com/gin-gonic/gin"
)

func InitRouter() *gin.Engine {
	r := gin.Default()

	user := r.Group("/api/user")
	{
		user.GET("/:id", controller.GetUser)      // 查询单个
		user.GET("", controller.GetUserList)      // 查询列表
		user.POST("", controller.CreateUser)      // 创建
		user.PUT("/:id", controller.UpdateUser)   // 更新
		user.DELETE("/:id", controller.DeleteUser) // 删除
	}

	return r
}
用原生的方式来实现RESTful
Go 复制代码
package router

import (
	"Web/controller"
	"net/http"
)

func InitRouter() {
	http.HandleFunc("/api/user", controller.UserHandler)    // 处理列表 & 创建
	http.HandleFunc("/api/user/", controller.UserIDHandler) // 处理查询/更新/删除
}
Go 复制代码
package controller

import (
	"fmt"
	"net/http"
	"strings"
)

func UserHandler(w http.ResponseWriter, r *http.Request) {
	switch r.Method {
	case "GET":
		GetUserList(w, r)
	case "POST":
		CreateUser(w, r)
	default:
		http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
	}
}

func UserIDHandler(w http.ResponseWriter, r *http.Request) {
	id := strings.TrimPrefix(r.URL.Path, "/api/user/") // 获取 id

	switch r.Method {
	case "GET":
		GetUser(w, r, id)
	case "PUT":
		UpdateUser(w, r, id)
	case "DELETE":
		DeleteUser(w, r, id)
	default:
		http.Error(w, "method not allowed", 405)
	}
}

四、Go Web 的分层设计

1. model:数据模型层

用于定义数据库表映射的结构体

Go 复制代码
package model

type User struct {
	ID       int64  `json:"id"`
	Username string `json:"username"`
	Password string `json:"password"`
	Email    string `json:"email"`
}

2. dao:数据库访问层

负责与 MySQL 进行交互:

Go 复制代码
package dao

import (
	"Web/model"
	"database/sql"
)

var DB *sql.DB

func GetUser(id int64) (*model.User, error) {
	user := &model.User{}
	err := DB.QueryRow("SELECT id, username, password,email FROM user WHERE id = ?", id).
		Scan(&user.ID, &user.Username, &user.Password, &user.Email)
	return user, err
}

func CreateUser(u *model.User) error {
	_, err := DB.Exec("INSERT INTO user (username, password,email) VALUES (?, ?,?)",
		u.Username, u.Password, u.Email)
	return err
}

func UpdateUser(u *model.User) error {
	_, err := DB.Exec("UPDATE user SET username=?, password=?,email=? WHERE id=?",
		u.Username, u.Password, u.Email, u.ID)
	return err
}

func DeleteUser(id int64) error {
	_, err := DB.Exec("DELETE FROM user WHERE id=?", id)
	return err
}

DAO 层只做数据库 CRUD,不处理任何业务逻辑。

3. service:业务层

对业务逻辑进行处理,例如校验、密码加密等:

Go 复制代码
package service

import (
	"Web/dao"
	"Web/model"
)

func GetUser(id int64) (*model.User, error) {
	return dao.GetUser(id)
}

func CreateUser(u *model.User) error {
	return dao.CreateUser(u)
}

func UpdateUser(u *model.User) error {
	return dao.UpdateUser(u)
}

func DeleteUser(id int64) error {
	return dao.DeleteUser(id)
}

Service 层不关心 HTTP,只关心业务。

4. controller:控制器层

接收 HTTP 请求、解析参数、返回响应:

Go 复制代码
package controller

import (
	"Web/model"
	"Web/service"
	"encoding/json"
	"log"
	"net/http"
	"strconv"
)

func GetUser(w http.ResponseWriter, r *http.Request) {
	idStr := r.URL.Query().Get("id")
	id, err := strconv.ParseInt(idStr, 10, 64)
	if err != nil {
		log.Println("转换为int类型错误")
		http.Error(w, "Invalid user ID", http.StatusBadRequest) // 400 错误
		return
	}

	user, err := service.GetUser(id)
	if err != nil {
		http.Error(w, "User Not Found", 404)
		return
	}

	encoder := json.NewEncoder(w)

	err = encoder.Encode(user)
	if err != nil {
		log.Println("写入流中错误", err)
		return
	}

}

func CreateUser(w http.ResponseWriter, r *http.Request) {
	var u model.User

	decoder := json.NewDecoder(r.Body)
	err := decoder.Decode(&u)
	if err != nil {
		http.Error(w, "Invalid JSON data: "+err.Error(), http.StatusBadRequest)
		return
	}

	if err := service.CreateUser(&u); err != nil {
		http.Error(w, "Create failed", 500)
		return
	}

	_, err = w.Write([]byte("ok"))
	if err != nil {
		log.Println("向流写入ok错误", err)
		return
	}
}

func UpdateUser(w http.ResponseWriter, r *http.Request) {
	var u model.User
	err := json.NewDecoder(r.Body).Decode(&u)
	if err != nil {
		http.Error(w, "Json转结构体错误: "+err.Error(), http.StatusBadRequest)
		return
	}

	if err := service.UpdateUser(&u); err != nil {
		http.Error(w, "Update failed", 500)
		return
	}

	_, err = w.Write([]byte("ok"))
	if err != nil {
		log.Println("向流写入ok错误", err)
		return
	}
}

func DeleteUser(w http.ResponseWriter, r *http.Request) {
	idStr := r.URL.Query().Get("id")
	id, err := strconv.ParseInt(idStr, 10, 64)
	if err != nil {
		log.Println("转换为int类型错误")
		http.Error(w, "Invalid user ID", http.StatusBadRequest)
		return
	}

	if err := service.DeleteUser(id); err != nil {
		http.Error(w, "Delete failed", 500)
		return
	}

	_, err = w.Write([]byte("ok"))
	if err != nil {
		log.Println("向流写入ok错误", err)
		return
	}
}

5.config:配置文件层

以连接mysql为例

Go 复制代码
package config

import (
	"database/sql"
	_ "github.com/go-sql-driver/mysql"
)

var DB *sql.DB

func InitDB() {
	db, err := sql.Open("mysql", "你的用户名:你的密码@tcp(127.0.0.1:3306)/要用的数据库名")
	if err != nil {
		panic(err)
	}
	DB = db
}

6.router:路由映射层

定义 URL 与控制器映射,即负责分发请求。一般要符合RESTful风格设计(详细请见本文第三部分)

五、前后端交互

采用JSON作为前后端数据交换格式,确保结构清晰且易于解析。前端发送请求时,后端将数据封装为JSON对象,后端返回时统一包含**code(状态码)、data(业务数据)、message(提示信息)**字段。

{

"code": 200,

"data": {...},

"message": "success"

}

字段 含义 示例
code 业务状态码 200 成功,400 参数错误,500 服务器错误
data 返回内容(结构体或数组) { "id":1, "name":"Tom" }
message 提示语 "操作成功""参数错误"
Go 复制代码
package response

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

type Result struct {
	Code    int         `json:"code"`
	Data    interface{} `json:"data,omitempty"`
	Message string      `json:"message"`
}

func Success(c *gin.Context, data interface{}) {
	c.JSON(200, Result{200, data, "success"})
}

func Fail(c *gin.Context, message string) {
	c.JSON(400, Result{400, nil, message})
}

一般创建如此的响应结构来封装。

六、服务启动 main.go

Go 复制代码
package main

import (
	"Web/config"
	"Web/router"
	"fmt"
	_ "github.com/go-sql-driver/mysql"
	"log"
	"net/http"
)

func main() {
	config.InitDB()
	router.InitRouter()
	fmt.Println("server running on :8080")
	err := http.ListenAndServe(":8080", cors(http.DefaultServeMux))
	if err != nil {
		log.Println(err)
		return
	}
}

func cors(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Access-Control-Allow-Origin", "*")
		w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
		w.Header().Set("Access-Control-Allow-Headers", "Content-Type")

		if r.Method == "OPTIONS" {
			return
		}
		next.ServeHTTP(w, r)
	})
}

cors函数用于解决前端和 Go 后端之间的跨域请求问题,让不同域名 / 端口的前端页面能正常调用 Go 后端接口。

七、项目部署

分别编写前后端的Dockerfile以及Nginx 反向代理配置

再通过容器编排实现。

自动启动:

  • MySQL 数据库

  • Go Web 后端服务

  • Vue/React 前端静态站点 (Nginx 托管)

  • 反向代理 Nginx(转发 /api 到 Go)

至此,一个web项目的开发基本就完成了。

相关推荐
南猿北者1 小时前
go语言基础语法
开发语言·后端·golang
镜花水月linyi1 小时前
1.5w字ReentrantLock 深度解析
java·后端·程序员
bot5556661 小时前
企业微信iPad协议:从接口设计到灰度验证的极简实践
后端
CC.GG1 小时前
【Qt】Qt初识
开发语言·qt
程序员西西2 小时前
Spring Boot3 分页操作全解析:从基础到实战
java·后端·程序员
用户68545375977692 小时前
为什么Python大神都在用with?看完我悟了
后端
mudtools2 小时前
一分钟实现.NET与飞书长连接的WebSocket架构
后端·c#·.net
Mcband2 小时前
【Spring Boot】Interceptor的原理、配置、顺序控制及与Filter的关键区别
java·spring boot·后端
qq_348231852 小时前
Spring Boot 体系核心全解
java·spring boot·后端