[go]gin框架
gin框架基础使用-梳理版
- 最简单的gin启服务
package main
import "github.com/gin-gonic/gin"
func main() {
r := gin.Default()
r.Run() //端口默认8080
}
RESPONSE RENDERING
context.go
- 返回字符串
func main() {
r := gin.Default()
r.POST("/", func(c *gin.Context) {
body, _ := ioutil.ReadAll(c.Request.Body)
c.String(http.StatusOK, "Put,%s", body)
})
r.Run()
}
- 返回json
func main() {
r := gin.Default()
//返回json
r.GET("/", func(c *gin.Context) {
c.JSON(200, gin.H{
"name": "mm",
"age": 22,
})
})
//返回map
m := map[string]int{}
m["m1"] = 11
m["m2"] = 12
r.GET("/map", func(c *gin.Context) {
c.JSON(200, m)
})
//返回struct
r.GET("/struct", func(c *gin.Context) {
c.JSON(200, struct {
Name string
Age int
}{"m1", 22})
})
r.Run()
}
- 渲染template和静态文件
func main() {
r := gin.Default()
r.LoadHTMLGlob("templates/*")
r.Static("/static", "./static")
r.GET("/", func(c *gin.Context) {
c.HTML(200, "index.html", nil)
})
r.Run()
}
context.go: RESPONSE RENDERING部分源码
- 请求头相关
//设置response status
func (c *Context) Status(code int)
//设置response header
func (c *Context) Header(key, value string) //快捷方式 c.Writer.Header().Set(key, value)
//获取request header
func (c *Context) GetHeader(key string) string
//获取stream的原生数据
func (c *Context) GetRawData() ([]byte, error)
//设置response header: Set-Cookie
func (c *Context) SetCookie(name, value string, maxAge int, path, domain string, secure, httpOnly bool)
//获取request的cookie
func (c *Context) Cookie(name string) (string, error)
//写入status/response header/content type 并执行渲染
func (c *Context) Render(code int, r render.Render)
c.Status(code)
r.WriteContentType(c.Writer)
c.Writer.WriteHeaderNow()
r.Render(c.Writer)
//HTML renders
func (c *Context) HTML(code int, name string, obj interface{})
// IndentedJSON serializes
// SecureJSON serializes
// JSONP serializes
// JSON serializes
func (c *Context) JSON(code int, obj interface{})
// AsciiJSON serializes
// PureJSON serializes
// XML serializes
// YAML serializes
// ProtoBuf serializes
func (c *Context) ProtoBuf(code int, obj interface{})
// String writes: the given string into the response body.
func (c *Context) String(code int, format string, values ...interface{})
// Redirect returns a HTTP redirect to the specific location.
func (c *Context) Redirect(code int, location string)
- 字符串
// Data writes some data into the body stream and updates the HTTP code.
func (c *Context) Data(code int, contentType string, data []byte)
// DataFromReader writes the specified reader into the body stream and updates the HTTP code.
- 文件相关
// File writes the specified file into the body stream in a efficient way.
func (c *Context) File(filepath string)
// FileAttachment writes the specified file into the body stream in an efficient way
func (c *Context) FileAttachment(filepath, filename string)
- 长连接相关
// SSEvent writes a Server-Sent Event into the body stream.
// Stream sends a streaming response and returns a boolean
INPUT DATA
context.go
- ?name=mm
func main() {
r := gin.Default()
r.GET("/", func(c *gin.Context) {
//name := c.DefaultQuery("name", "default name")
name := c.Query("name")
c.JSON(200, gin.H{"name": name})
})
r.Run()
}
?name=mm&name=m2
func main() {
r := gin.Default()
r.GET("/", func(c *gin.Context) {
names := c.QueryArray("name")
c.JSON(200, gin.H{"name": names})
})
r.Run()
}
//{
// name: [
// "mm",
// "m2"
// ]
//}
- /mm/22/
func main() {
r := gin.Default()
r.GET("/:name/:age", func(c *gin.Context) {
name := c.Param("name")
age := c.Param("age")
c.JSON(200, gin.H{"name": name, "age": age})
})
r.Run()
}
- 收到表单数据 - 获取数据
<body>
<form action="http://localhost:8080/" method="post">
<input type="text" name="name">
<input type="text" name="age">
<input type="submit">
</form>
</body>
func main() {
r := gin.Default()
r.POST("/", func(c *gin.Context) {
name := c.PostForm("name")
age := c.PostForm("age")
c.JSON(200, gin.H{"name": name, "age": age})
})
r.Run()
}
- 收到表单数据 - 绑定到结构体
name=m1 age=22
<body>
<form action="http://localhost:8080/" method="post">
<input type="text" name="name">
<input type="text" name="age">
<input type="submit">
</form>
</body>
type User struct {
Name string `form:"name" binding:"required"`
Age int `form:"age" binding:"required"`
}
func main() {
r := gin.Default()
r.POST("/", func(c *gin.Context) {
var user User
// This will infer what binder to use depending on the content-type header.
if err := c.ShouldBind(&user); err == nil {
c.JSON(http.StatusOK, gin.H{
"name": user.Name,
"age": user.Age,
})
} else {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
}
})
r.Run()
}
- 收到json数据 - 绑定到结构体
{"name":"m1","age":22}
type User struct {
Name string `json:"name" binding:"required"`
Age int `json:"age" binding:"required"`
}
func main() {
r := gin.Default()
r.POST("/", func(c *gin.Context) {
var user User
// This will infer what binder to use depending on the content-type header.
if err := c.ShouldBind(&user); err == nil {
c.JSON(http.StatusOK, gin.H{
"name": user.Name,
"age": user.Age,
})
} else {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
}
})
r.Run()
}
- 收到url数据, 绑定到结构体
?name=mm&age=22
type User struct {
Name string `form:"name" binding:"required"`
Age int `form:"age" binding:"required"`
}
func main() {
r := gin.Default()
r.GET("/", func(c *gin.Context) {
var user User
// This will infer what binder to use depending on the content-type header.
if err := c.ShouldBind(&user); err == nil {
c.JSON(http.StatusOK, gin.H{
"name": user.Name,
"age": user.Age,
})
} else {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
}
})
r.Run()
}
- 收到表单数据 - 绑定到结构体
/?Name=mm&Age=22
type User struct {
Name string `binding:"required"`
Age int `binding:"required"`
}
/?Name=mm
type User struct {
Name string `binding:"required"`
Age int //允许age不传, 默认零值
}
context.go: INPUT DATA源码
//返回url的参数, eg:/user/john /user/:id 则id=="john"
// c.Params.ByName(key) 的快捷方式
// router.GET("/user/:id", func(c *gin.Context) {
// // a GET request to /user/john
// id := c.Param("id") // id == "john"
// })
func (c *Context) Param(key string) string
//返回keyed url的查询参数, 如果不存在则返回""
// c.Request.URL.Query().Get(key)的快捷方式
// GET /path?id=1234&name=Manu&value=
// c.Query("id") == "1234"
// c.Query("name") == "Manu"
// c.Query("value") == ""
// c.Query("wtf") == ""
func (c *Context) Query(key string) string
//返回keyed url的查询参数, 如果不存在,则返回指定的值
// GET /?name=Manu&lastname=
// c.DefaultQuery("name", "unknown") == "Manu"
// c.DefaultQuery("id", "none") == "none"
// c.DefaultQuery("lastname", "none") == ""
func (c *Context) DefaultQuery(key, defaultValue string) string
func (c *Context) GetQuery(key string) (string, bool)
func (c *Context) QueryArray(key string) []string
func (c *Context) GetQueryArray(key string) ([]string, bool)
func (c *Context) QueryMap(key string) map[string]string
func (c *Context) GetQueryMap(key string) (map[string]string, bool)
func (c *Context) PostForm(key string) string
func (c *Context) GetPostForm(key string) (string, bool)
func (c *Context) DefaultPostForm(key, defaultValue string) string
func (c *Context) GetPostForm(key string) (string, bool)
func (c *Context) GetPostFormArray(key string) ([]string, bool)
func (c *Context) GetPostFormArray(key string) ([]string, bool)
func (c *Context) PostFormMap(key string) map[string]string
func (c *Context) GetPostFormMap(key string) (map[string]string, bool)
func (c *Context) get(m map[string][]string, key string) (map[string]string, bool)
func (c *Context) FormFile(name string) (*multipart.FileHeader, error)
func (c *Context) MultipartForm() (*multipart.Form, error)
func (c *Context) SaveUploadedFile(file *multipart.FileHeader, dst string)
//根据content-type 绑定engine
func (c *Context) Bind(obj interface{}) error
func (c *Context) BindJSON(obj interface{}) error
func (c *Context) BindXML(obj interface{}) error
c.MustBindWith(obj, binding.BindXML)
func (c *Context) BindQuery(obj interface{}) error
func (c *Context) BindYAML(obj interface{}) error
func (c *Context) BindHeader(obj interface{}) error
func (c *Context) BindUri(obj interface{}) error
func (c *Context) MustBindWith(obj interface{}, b binding.Binding) error
...ShouldBind
func (c *Context) ClientIP() string
func (c *Context) ContentType() string
func (c *Context) IsWebsocket() bool
func (c *Context) requestHeader(key string) string
路由
- 路由组
func main() {
r := gin.Default()
v1 := r.Group("/v1")
{
// /v1/
v1.GET("/", func(c *gin.Context) {
c.JSON(200, gin.H{"name": "m1"})
})
// /v1/test
v1.GET("/test", func(c *gin.Context) {
c.JSON(200, gin.H{"name": "m1 test"})
})
}
v2 := r.Group("/v2")
v2.GET("/", func(c *gin.Context) {
c.JSON(200, gin.H{"name": "m2"})
})
v2.GET("/test", func(c *gin.Context) {
c.JSON(200, gin.H{"name": "m2 test"})
})
r.Run()
}
gin框架-基础使用
Gin框架返回值
// 返回json
func main() {
r := gin.Default()
//方法一: 自己拼接json
// gin.H is a shortcut for map[string]interface{}
r.GET("/someJSON", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK})
})
//方法2: 返回结构体对象
r.GET("/moreJSON", func(c *gin.Context) { // You also can use a struct
var msg struct {
Name string `json:"user"`
Message string
Number int
}
msg.Name = "Lena"
msg.Message = "hey"
msg.Number = 123
// Note that msg.Name becomes "user" in the JSON
c.JSON(http.StatusOK, msg)
})
// Listen and serve on 0.0.0.0:8080
r.Run(":8080")
}
// 渲染html
router.LoadHTMLGlob("templates/*")
router.Static("/static", "./static")
func main() {
router := gin.Default()
router.LoadHTMLGlob("templates/*") // LoadHTMLFiles只会加载一个文件
router.Static("/static", "./static") //第二个参数相对于执行路径
//渲染静态目录
router.GET("/", func(c *gin.Context) {
c.HTML(http.StatusOK, "index.html", nil)
})
router.Run(":8000")
}
Gin框架参数传递
//获取参数 querystring
/user/search?name=mm&age=22
r.GET("/user/search", func(c *gin.Context)
name := c.DefaultQuery("name", "mm") // 赋默认值
name := c.Query("name")
func main() {
r := gin.Default()
r.GET("/user/search", func(c *gin.Context) {
name := c.DefaultQuery("name", "mm")
//name := c.Query("name")
age := c.Query("age")
//输出json结果给调用方
c.JSON(200, gin.H{
"message": "pong",
"name": name,
"age": age,
})
})
r.Run() // listen and serve on 0.0.0.0:8080
}
// 获取参数 path
/user/search/mm/22
r.GET("/user/search/:name/:age", func(c *gin.Context)
name := c.Param("mm")
func main() {
r := gin.Default()
r.GET("/user/search/:name/:age", func(c *gin.Context) {
name := c.Param("mm")
age := c.Param("age")
//输出json结果给调用方
c.JSON(200, gin.H{
"message": "pong",
"username": username,
"address": address,
})
})
r.Run(":8080") // listen and serve on 0.0.0.0:8080
}
// 获取参数: form提交
r.POST("/user/search", func(c *gin.Context) {
name := c.DefaultPostForm("name", "mm")
name := c.PostForm("name")
func main() {
r := gin.Default()
r.POST("/user/search", func(c *gin.Context) {
//name := c.DefaultPostForm("name", "mm")
name := c.PostForm("name")
age := c.PostForm("age")
//输出json结果给调用方
c.JSON(200, gin.H{
"message": "pong",
"name": name,
"age": age,
})
})
r.Run(":8080")
}
// Binding from JSON
type Login struct {
User string `form:"user" json:"user" binding:"required"`
Password string `form:"password" json:"password" binding:"required"`
}
func main() {
router := gin.Default()
// Example for binding JSON ({"user": "manu", "password": "123"})
router.POST("/loginJSON", func(c *gin.Context) {
var login Login
if err := c.ShouldBindJSON(&login); err == nil {
fmt.Printf("login info:%#v\n", login)
c.JSON(http.StatusOK, gin.H{
"user": login.User,
"password": login.Password,
})
} else {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
}
})
// Example for binding a HTML form (user=manu&password=123)
router.POST("/loginForm", func(c *gin.Context) {
var login Login
// This will infer what binder to use depending on the content-type header.
if err := c.ShouldBind(&login); err == nil {
c.JSON(http.StatusOK, gin.H{
"user": login.User,
"password": login.Password,
})
} else {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
}
})
// Example for binding a HTML querystring (user=manu&password=123)
router.GET("/loginForm", func(c *gin.Context) {
var login Login
// This will infer what binder to use depending on the content-type header.
if err := c.ShouldBind(&login); err == nil {
c.JSON(http.StatusOK, gin.H{
"user": login.User,
"password": login.Password,
})
} else {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
}
})
// Listen and serve on 0.0.0.0:8080
router.Run(":8080")
}
gin Restful
// restful风格
func main() {
//Default返回一个默认的路由引擎
r := gin.Default()
r.GET("/user/info", func(c *gin.Context) {
//输出json结果给调用方
c.JSON(200, gin.H{
"message": "get user info succ",
})
})
r.POST("/user/info", func(c *gin.Context) {
//输出json结果给调用方
c.JSON(200, gin.H{
"message": "create user info succ",
})
})
r.PUT("/user/info", func(c *gin.Context) {
//输出json结果给调用方
c.JSON(200, gin.H{
"message": "update user info succ",
})
})
r.DELETE("/user/info", func(c *gin.Context) {
//输出json结果给调用方
c.JSON(200, gin.H{
"message": "delete user info succ ",
})
})
r.Run() // listen and serve on 0.0.0.0:8080
}
// 版本管理
func login(ctx *gin.Context) {
ctx.JSON(200, gin.H{
"message": "success",
})
}
func read(ctx *gin.Context) {
ctx.JSON(200, gin.H{
"message": "success",
})
}
func submit(ctx *gin.Context) {
ctx.JSON(200, gin.H{
"message": "success",
})
}
func main() {
//Default返回一个默认的路由引擎
router := gin.Default()
// Simple group: v1
// /v1/login
// /v1/submit
// /v1/read
v1 := router.Group("/v1")
{
v1.POST("/login", login)
v1.POST("/submit", submit)
v1.POST("/read", read)
}
// Simple group: v2
// /v2/login
// /v2/submit
// /v2/read
v2 := router.Group("/v2")
{
v2.POST("/login", login)
v2.POST("/submit", submit)
v2.POST("/read", read)
}
router.Run(":8080")
}
Gin中间件
//计算请求耗时
func StatCost() gin.HandlerFunc {
return func(c *gin.Context) {
t := time.Now()
//可以设置一些公共参数
c.Set("example", "12345")
//等其他中间件先执行
c.Next()
//获取耗时
latency := time.Since(t)
log.Printf("total cost time:%d us", latency/1000)
}
}
func main() {
//r := gin.New()
r := gin.Default()
r.Use(StatCost())
r.GET("/test", func(c *gin.Context) {
example := c.MustGet("example").(string)
// it would print: "12345"
log.Println(example)
c.JSON(http.StatusOK, gin.H{
"message": "success",
})
})
// Listen and serve on 0.0.0.0:8080
r.Run()
}
// 从第三方获取数据
func main() {
router := gin.Default()
router.GET("/someDataFromReader", func(c *gin.Context) {
response, err := http.Get("https://raw.githubusercontent.com/gin-gonic/logo/master/color.png")
if err != nil || response.StatusCode != http.StatusOK {
c.Status(http.StatusServiceUnavailable)
return
}
reader := response.Body
contentLength := response.ContentLength
contentType := response.Header.Get("Content-Type")
extraHeaders := map[string]string{
"Content-Disposition": `attachment; filename="gopher.png"`,
}
c.DataFromReader(http.StatusOK, contentLength, contentType, reader, extraHeaders)
})
router.Run(":8080")
}
Gin写日志
//写日志到文件
func main() {
// Disable Console Color, you don't need console color when writing the logs to file.
gin.DisableConsoleColor()
// Logging to a file.
f, _ := os.Create("/tmp/gin.log")
gin.DefaultWriter = io.MultiWriter(f)
// Use the following code if you need to write the logs to file and console at the same time.
// gin.DefaultWriter = io.MultiWriter(f, os.Stdout)
//Default返回一个默认的路由引擎
r := gin.Default()
r.GET("/ping", func(c *gin.Context) {
//输出json结果给调用方
c.JSON(200, gin.H{
"message": "pong",
})
})
r.Run() // listen and serve on 0.0.0.0:8080
}
// 自定义日志格式
func main() {
router := gin.New()
// LoggerWithFormatter 中间件会将日志写入 gin.DefaultWriter
// By default gin.DefaultWriter = os.Stdout
router.Use(gin.LoggerWithFormatter(func(param gin.LogFormatterParams) string {
// 你的自定义格式
return fmt.Sprintf("%s - [%s] \"%s %s %s %d %s \"%s\" %s\"\n",
param.ClientIP,
param.TimeStamp.Format(time.RFC1123),
param.Method,
param.Path,
param.Request.Proto,
param.StatusCode,
param.Latency,
param.Request.UserAgent(),
param.ErrorMessage,
)
}))
router.Use(gin.Recovery())
router.GET("/ping", func(c *gin.Context) {
c.String(200, "pong")
})
router.Run(":8080")
}
获取header和body
func main() {
r := gin.Default()
r.POST("/", func(c *gin.Context) {
for k, v := range c.Request.Header {
fmt.Println(k, v)
}
body, _ := ioutil.ReadAll(c.Request.Body)
fmt.Println(string(body))
c.JSON(200, gin.H{"name": "m1"})
})
r.Run()
}
//Content-Type [application/json]
//Cache-Control [no-cache]
//Content-Length [22]
//User-Agent [PostmanRuntime/7.21.0]
//Accept [*/*]
//Postman-Token [471de3df-7a5c-4e22-a92f-33eacd076722]
//Accept-Encoding [gzip, deflate]
//Connection [keep-alive]
//{"name":"m1","age":22}
[go]gin框架的更多相关文章
- 基于gin框架和jwt-go中间件实现小程序用户登陆和token验证
本文核心内容是利用jwt-go中间件来开发golang webapi用户登陆模块的token下发和验证,小程序登陆功能只是一个切入点,这套逻辑同样适用于其他客户端的登陆处理. 小程序登陆逻辑 小程序的 ...
- gin框架使用注意事项
gin框架使用注意事项 本文就说下这段时间我在使用gin框架过程中遇到的问题和要注意的事情. 错误处理请求返回要使用c.Abort,不要只是return 当在controller中进行错误处理的时候, ...
- Gin框架源码解析
Gin框架源码解析 Gin框架是golang的一个常用的web框架,最近一个项目中需要使用到它,所以对这个框架进行了学习.gin包非常短小精悍,不过主要包含的路由,中间件,日志都有了.我们可以追着代码 ...
- gin框架学习手册
前言 gin框架是go语言的一个框架,框架的github地址是:https://github.com/gin-gonic/gin 转载本文,请标注原文地址:https://www.cnblogs.co ...
- go的gin框架从请求中获取参数的方法
前言: go语言的gin框架go里面比较好的一个web框架, github的start数超过了18000.可见此框架的可信度 如何获取请求中的参数 假如有这么一个请求: POST /post/te ...
- Go语言基础之20--web编程框架之Gin框架
一.Gin框架介绍 1.1 简介 A. 基于httprouter开发的web框架. http://github.com/julienschmidt/httprouter B. 提供Martini风格的 ...
- Gin 框架 - 安装和路由配置
目录 概述 Gin 安装 路由配置 推荐阅读 概述 看下 Gin 框架的官方介绍: Gin 是一个用 Go (Golang) 编写的 web 框架. 它是一个类似于 martini 但拥有更好性能的 ...
- Gin 框架 - 使用 logrus 进行日志记录
目录 概述 日志格式 Logrus 使用 推荐阅读 概述 上篇文章分享了 Gin 框架的路由配置,这篇文章分享日志记录. 查了很多资料,Go 的日志记录用的最多的还是 github.com/sirup ...
- [系列] Gin框架 - 数据绑定和验证
目录 概述 推荐阅读 概述 上篇文章分享了 Gin 框架使用 Logrus 进行日志记录,这篇文章分享 Gin 框架的数据绑定与验证. 有读者咨询我一个问题,如何让框架的运行日志不输出控制台? 解决方 ...
- Gin框架 - 自定义错误处理
目录 概述 错误处理 自定义错误处理 panic 和 recover 推荐阅读 概述 很多读者在后台向我要 Gin 框架实战系列的 Demo 源码,在这里再说明一下,源码我都更新到 GitHub 上, ...
随机推荐
- 【Distributed】分布式任务调度平台
一.概述 什么是定时任务 二.Java实现定时任务方式 2.1 Thread 2.2 TimerTask 2.3 ScheduledExecutorService 2.4 Quartz 引入maven ...
- 第三章、vue-项目前端 - vue配置 | axios配置 | cookies配置 | element-ui配置 | bootstrap配置
目录 vue项目创建 环境 创建项目 重构项目目录 文件修订:目录中非配置文件的多余文件可以移除 全局配置:全局样式.配置文件 axios前后台交互 cookies操作 element-ui页面组件框 ...
- Java与CC++交互JNI编程
哈哈,经过了前面几个超级枯燥的C.C++两语言的基础巩固之后,终于来了到JNI程序的编写了,还是挺不容易的,所以还得再接再厉,戒骄戒躁,继续前行!! 第一个JNI程序: JNI是一种本地编程接口.它允 ...
- Ubuntu死机解决方法汇总
为什么不建议强制关机 如果长按电源按键强制关机,有可能损坏硬件或者丢失数据,甚至导致磁盘坏道! 其实, 大部分时候的死机是假死, 不是真死... 有时候鼠标还能动呢. 还有一个原因: 对于平时忠贞不二 ...
- window程序意外关闭自动重启脚本实现
@echo off : tasklist|find /i "xxxx"||start yyyy ping/n 127.1>nul 新建 .bat 文件,将其写入文件 xxxx ...
- PHP批量更新MYSQL中的数据
原文链接:https://blog.csdn.net/wuming19900801/article/details/62893429 $sql = "update newhouse_clic ...
- Python中正则匹配使用findall,捕获分组(xxx)和非捕获分组(?:xxx)的差异
转自:https://blog.csdn.net/qq_42739440/article/details/81117919 下面是我在用findall匹配字符串时遇到的一个坑,分享出来供大家跳坑. 例 ...
- flutter 编译报错 ../extended_network_image_provider.dart:63:41: Error: Type 'DecoderCallback' not found
flutter 编译的时候报错 Compiler message:../../../.pub-cache/hosted/pub.dartlang.org/extended_image_library- ...
- java 正则《转载》
Java 正则表达式 正则表达式定义了字符串的模式. 正则表达式可以用来搜索.编辑或处理文本. 正则表达式并不仅限于某一种语言,但是在每种语言中有细微的差别. 正则表达式实例 一个字符串其实就是一个简 ...
- winfrom窗体自适应
using System.Runtime.InteropServices; public class Win32 { public const Int32 AW_HOR_POSITIVE = 0x00 ...