响应
json 响应
对Response 封装
package res
import "github.com/gin-gonic/gin"
type Response struct { Code int `json:"code"` Msg string `json:"msg"` Data any `json:"data"`}
var codeMap = map[int]string{ 1001: "权限错误", 1002: "角色错误", 1003: "参数错误",}
func response(context *gin.Context, code int, data any, msg string) { context.JSON(200, Response{ Code: code, Msg: msg, Data: data, })}func Ok(context *gin.Context, data any, msg string) { response(context, 0, data, msg)}
func OkWithData(context *gin.Context, data any) { Ok(context, data, "操作成功")}
func OkWithMsg(context *gin.Context, msg string) { Ok(context, gin.H{}, msg)}
// 错误的封装func Fail(context *gin.Context, code int, data any, msg string) { response(context, code, data, msg)}
func FailWithMsg(context *gin.Context, msg string) { response(context, 1001, nil, msg)
}
func FailWithCode(context *gin.Context, code int) { msg, ok := codeMap[code] if !ok { msg = "服务错误" } response(context, code, nil, msg)}-
response是唯一的实际出口,所有 HTTP 状态码都固定写200(enter.go:12),把“业务状态”和“HTTP 状态”分离——HTTP 永远 200,业务成功失败靠code字段表达。这是 RESTful 风格之外另一种常见约定(国内项目很流行)。 -
业务代码只调
Ok/Fail,不直接碰response,保证所有响应都走同一个出口,不会有人偷偷返回不一样的格式。 -
只关心数据 →
OkWithData(c, user)自动填“操作成功” -
只关心提示 →
OkWithMsg(c, "删除成功")自动填空data
好处:handler 代码更短、更聚焦业务,不用每次都手写 msg。这是“语法糖”,没有它们用 Ok 也能做到,但写了能少敲很多字。
package main
import ( "gin_study/study_response/res"
"github.com/gin-gonic/gin")
func main() { //初始化 r := gin.Default() //绑定路由 r.GET("/login", func(context *gin.Context) { res.OkWithMsg(context, "成功") }) r.GET("/users", func(context *gin.Context) { res.OkWithData(context, map[string]any{ "name": "张三", "age": 18, }) }) r.POST("/users", func(context *gin.Context) { res.FailWithMsg(context, "失败") }) //绑定端口运行 r.Run(":8080")}html 响应
使用LoadHTMLGlob加载一个目录下的所有html文件
也可以使用LoadHTMLFiles加载单个html文件
load之后,下面才能用这个文件名
package main
import "github.com/gin-gonic/gin"
func main() { r := gin.Default() // 加载模板 只有这里加载了模板,下面才能用 r.LoadHTMLGlob("templates/*") //r.LoadHTMLFiles("templates/index.html") r.GET("", func(c *gin.Context) { c.HTML(200, "index.html", nil) }) r.Run(":8080")}HTML的第三个参数是可以向HTML中传递数据
但是现在都是前后端分离的时代了,也很少使用后端返回模板了,知道怎么用就好
c.HTML(200, "index.html", map[string]any{ "title": "这是网页标题", })html文件中使用
<title>{{.title}}</title>其实借助这个功能,可以很方便的修改网站的标题和logo
响应文件
用于浏览器直接请求这个接口唤起下载
c.Header("Content-Type", "application/octet-stream") // 表示是文件流,唤起浏览器下载,一般设置了这个,就要设置文件名c.Header("Content-Disposition", "attachment; filename=3.文件下载.go") // 用来指定下载下来的文件名c.File("3.文件下载.go")- 要设置Content-Type,唤起浏览器下载
- 只能是get请求
前端请求后端接口,然后唤起浏览器下载
c.Header("fileName", "xxx.png")c.Header("msg", "文件下载成功")c.File("uploads/12.png")最好的做法
调下载接口的请求,后端不返回实际文件内容,而是生成一个临时下载地址
前端构造a标签,再请求这个接口唤起浏览器下载
静态文件
r.Static("st" /*别名*/, "static")// 第一个参数是别名,第二个才是实际路径 //http://localhost:8080/st/hello.txt r.StaticFile("abc", "static/hello.txt") //http://localhost:8080/abc静态文件的路径,不能再被路由使用了
请求
查询参数
?key=xxx&name=xxxx&name=yyyy 这种就被称为查询参数
查询参数不是GET请求专属的
r.GET("", func(c *gin.Context) { name := c.Query("name") age := c.DefaultQuery("age", "25") keyList := c.QueryArray("key") fmt.Println(name, age, keyList) })//http://localhost:8080/?name=zhangsan&age=18&key=123&key=333zhangsan 18 [123 333]动态参数
用户的个人信息页面,他的路径
/users?id=123 // 查询参数的模式/users/123 // 动态参数模式 r.GET("users/:id/:name", func(c *gin.Context) { userId := c.Param("id") userName := c.Param("name") fmt.Println(userId, userName) })表单参数
form 表单
r.POST("users", func(c *gin.Context) { name := c.PostForm("name") //通过 ok 来判断是否传了数据 age, ok := c.GetPostForm("age") fmt.Println(name, age, ok)
})文件上传
r.POST("users", func(c *gin.Context) { fileHeader, err := c.FormFile("file") if err != nil { fmt.Println(err) return } fmt.Println(fileHeader.Filename) //文件名 fmt.Println(fileHeader.Size) //单位是字节 file, _ := fileHeader.Open() byteData, _ := io.ReadAll(file) err = os.WriteFile("xxx.jpg", byteData, 0666) fmt.Println(err)
})简单的方法
err = c.SaveUploadedFile(fileHeader, "uploads/"+fileHeader.Filename) fmt.Println(err)多文件
r.POST("users", func(c *gin.Context) { form, err := c.MultipartForm() if err != nil { fmt.Println(err) return } for _, headers := range form.File { for _, header := range headers { c.SaveUploadedFile(header, "uploads/muilt/"+header.Filename) }
} })接口测试工具
Postman
apifox
注意:接口测试工具能走通的,前端请求不一定可以走通
- get请求带请求体
- ws加请求头


