Gin 学习笔记 01-Go 原生 HTTP 服务和 Gin 初始化

Go 原生 HTTP 服务

一个最简单的例子

package main

import (
	"fmt"
	"net/http"
)

func main() {
	//注册路由:访问 /hello 时执行这个函数
	http.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintln(w, "hello world")
	})

	//启动服务,监听 8080 端口
	fmt.Println("服务启动:http://localhost:8080")
	http.ListenAndServe(":8080", nil)
}

运行之后访问 http://localhost:8080/hello,浏览器上就会出现 hello world

几个关键点

  • http.HandleFunc 用来注册路由,第一个参数是路径,第二个是处理函数。
  • 处理函数的签名是固定的:func(w http.ResponseWriter, r *http.Request)
    • w 用来写响应(返回给前端的内容)。
    • r 用来读请求(请求头、参数、请求体等)。
  • http.ListenAndServe(":8080", nil) 启动服务,第二个参数传 nil 表示用默认的 DefaultServeMux(也就是上面 HandleFunc 注册的那些路由)。

获取请求参数

package main

import (
	"fmt"
	"net/http"
)

func main() {
	http.HandleFunc("/user", func(w http.ResponseWriter, r *http.Request) {
		//获取 query 参数,例如 /user?id=1
		id := r.URL.Query().Get("id")
		fmt.Fprintf(w, "用户ID:%s", id)
	})

	http.HandleFunc("/login", func(w http.ResponseWriter, r *http.Request) {
		//解析表单
		r.ParseForm()
		username := r.Form.Get("username")
		password := r.Form.Get("password")
		fmt.Fprintf(w, "用户名:%s,密码:%s", username, password)
	})

	http.ListenAndServe(":8080", nil)
}

返回 JSON

原生返回 JSON 也比较麻烦,需要先定义结构体,再手动序列化,再设置响应头。

package main

import (
	"encoding/json"
	"net/http"
)

type User struct {
	Name string `json:"name"`
	Age  int    `json:"age"`
}

func main() {
	http.HandleFunc("/json", func(w http.ResponseWriter, r *http.Request) {
		user := User{Name: "张三", Age: 18}
		//设置响应头
		w.Header().Set("Content-Type", "application/json")
		//序列化并写入
		json.NewEncoder(w).Encode(user)
	})

	http.ListenAndServe(":8080", nil)
}

安装 Gin

go get -u github.com/gin-gonic/gin

-u 表示更新到最新版本。

装完之后,go.mod 里会多出一行:

require github.com/gin-gonic/gin v1.x.x

一个最简单的 Gin 示例

package main

import (
	"net/http"

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

func main() {
	//初始化引擎
	r := gin.Default()

	//注册路由
	r.GET("/hello", func(c *gin.Context) {
		c.String(http.StatusOK, "hello world")
	})

	r.GET("/json", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{
			"name": "张三",
			"age":  18,
		})
	})

	//启动服务
	r.Run(":8080")
}

运行之后:

  • 访问 http://localhost:8080/hello,返回 hello world
  • 访问 http://localhost:8080/json,返回一段 JSON。

几个关键点

  • gin.Default() 创建一个带默认中间件(日志和错误恢复)的引擎。
    • 如果不想要默认中间件,可以用 gin.New(),然后自己加。
  • r.GET 注册一个 GET 路由,同理还有 r.POSTr.PUTr.DELETE 等。
  • 处理函数的签名是 func(c *gin.Context)c 既能读请求也能写响应,比原生的 wr 方便很多。
  • c.String 返回字符串,c.JSON 返回 JSON,gin.Hmap[string]any 的简写。
  • r.Run(":8080") 启动服务,内部其实也是调用了 http.ListenAndServe

关闭 Gin 自带的调试日志

启动 Gin 时,控制台默认会打印一大段带有 [GIN-debug] 的彩色日志(路由表、警告、监听地址等)。开发时方便排查问题,但有时候输出太多,或者生产环境不想要这些,可以关掉。

Gin 是通过环境变量 GIN_MODE 控制运行模式的,有三个值:

  • debug(默认):打印调试日志。
  • release:生产模式,关闭调试日志,性能更好。
  • test:测试模式。

方式一:代码里设置

package main

import (
	"net/http"

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

func main() {
	//设置成 release 模式,关闭调试日志
	gin.SetMode(gin.ReleaseMode)

	r := gin.Default()
	r.GET("/hello", func(c *gin.Context) {
		c.String(http.StatusOK, "hello world")
	})
	r.Run(":8080")
}

注意:gin.SetMode 要放在 gin.Default()(或 gin.New()之前调用,否则不生效。

方式二:通过环境变量

也可以不改代码,直接在启动前设置环境变量:

export GIN_MODE=release
go run main.go

或者在运行命令前临时指定:

GIN_MODE=release go run main.go

这种方式的好处是不用改代码,部署时可以灵活切换。

让局域网内的其他人访问

默认情况下,r.Run(":8080") 监听的是 0.0.0.0:8080

但如果之前写成了 r.Run("127.0.0.1:8080"),那就只能本机访问,其他人连不上。要允许局域网访问,监听地址不能写 127.0.0.1,用下面任一写法即可:

//方式一:省略 IP,只写端口,默认监听 0.0.0.0
r.Run(":8080")

//方式二:显式写 0.0.0.0
r.Run("0.0.0.0:8080")
  • 127.0.0.1(localhost):只接受本机请求,外面进不来。
  • 0.0.0.0:监听本机所有网卡,局域网内其他设备都能访问。