1: リクエストとリクエストバインディング
1.1: パスパラメータ
- : パラメータ名。中間部分を取ることを意味します。
- ※パラメータ名とは、取得後の全データを指します。
- パスパラメータ。 context.Param() で取得します。
- 場合:
package animal
import "github.com/gin-gonic/gin"
func Routers(e *gin.Engine) {
e.GET("/animal/:name/*action", testArgs)
}
package animal
import (
"github.com/gin-gonic/gin"
"net/http"
"strings"
)
func testArgs(context *gin.Context) {
name := context.Param("name")
action := context.Param("action")
action = strings.Split(action, "/")[2]
context.String(http.StatusOK, "name is %s, action is %s", name, action)
}
1.2: クエリ文字列パラメータ
- DefaultQuery() は、パラメータが存在しない場合はデフォルト値を返し、Query() が存在しない場合は空の文字列を返します。
- DefaultQuery() の場合:
package animal
import "github.com/gin-gonic/gin"
func Routers(e *gin.Engine) {
e.GET("/animal/login", testArgs)
}
package animal
import (
"github.com/gin-gonic/gin"
"net/http"
)
func testArgs(context *gin.Context) {
name := context.DefaultQuery("name", "root")
password := context.DefaultQuery("password", "123456")
context.String(http.StatusOK, "name is %s, password is %s。", name, password)
}
package animal
import (
"github.com/gin-gonic/gin"
"net/http"
)
func testArgs(context *gin.Context) {
name := context.Query("name")
password := context.Query("password")
if name == "" || password == "" {
context.String(http.StatusOK, "必要参数缺失")
} else {
context.String(http.StatusOK, "name is %s, password is %s。", name, password)
}
}
1.3: フォームパラメータ
- PostForm() はフォームパラメータを解析できます
func testArgs(context *gin.Context) {
name := context.PostForm("name")
password := context.PostForm("password")
if name == "" || password == "" {
context.String(http.StatusOK, "必要参数缺失")
} else {
context.String(http.StatusOK, "name is %s, password is %s。", name, password)
}
}
package animal
import (
"github.com/gin-gonic/gin"
"net/http"
)
func testArgs(context *gin.Context) {
file, err := context.FormFile("file")
if err != nil {
context.String(500, "file upload fail, err msg is %s", err)
return
}
err = context.SaveUploadedFile(file, file.Filename)
if err != nil {
context.String(500, "file save fail, err msg is %s", err)
return
}
context.String(http.StatusOK, file.Filename)
}
1.4: JSONデータ
- パラメータは構造体 context.ShouldBindJSON() にバインドされます。
- 注: まず、構造体オブジェクトをインスタンス化してから、構造体オブジェクトの参照を渡す必要があります。
- なぜアドレスを渡す必要があるのでしょうか?
- インスタンス化されたオブジェクトは変更する必要があるためです。オブジェクトを渡すことの本質が新しいオブジェクトをコピーすることである場合、現在のオブジェクトは変更されません。
package animal
import (
"github.com/gin-gonic/gin"
"net/http"
)
type LoginJsonArgs struct {
Name string `json:"name" binding:"required"`
Password string `json:"password" binding:"required"`
}
func testArgs(context *gin.Context) {
var loginArgs LoginJsonArgs
err := context.ShouldBindJSON(&loginArgs)
if err != nil {
context.JSON(http.StatusBadRequest, gin.H{
"error": err.Error()})
return
}
if loginArgs.Name != "root" && loginArgs.Password != "123456" {
context.JSON(http.StatusUnauthorized, gin.H{
"status": "401", "msg": "args validated fail"})
} else {
context.JSON(http.StatusOK, gin.H{
"status": "200", "msg": "login success"})
}
}
1.5: フォームは構造をバインドすることもできます
type LoginJsonArgs struct {
Name string `form:"name" binding:"required"`
Password string `form:"password" binding:"required"`
}
var loginArgs LoginJsonArgs
err := context.Bind(&loginArgs)
if err != nil {
context.JSON(http.StatusBadRequest, gin.H{
"error": err.Error()})
return
}
1.6: パスパラメータのバインディング
type LoginJsonArgs struct {
Name string `uri:"name" binding:"required"`
Password string `uri:"password" binding:"required"`
}
- バインド関数は ShouldBindUri() を受け取ります
var loginArgs LoginJsonArgs
err := context.ShouldBindUri(&loginArgs)
if err != nil {
context.JSON(http.StatusBadRequest, gin.H{
"error": err.Error()})
return
}
import "github.com/gin-gonic/gin"
func Routers(e *gin.Engine) {
e.GET("/animal/login/:name/:password", testArgs)
}
1.7: クエリ文字列バインディング
- この構造はバインディング パラメータを制限します。これは Form フォームと同じです。
type LoginJsonArgs struct {
Name string `form:"name" binding:"required"`
Password string `form:"password" binding:"required"`
}
var loginArgs LoginJsonArgs
err := context.ShouldBindQuery(&loginArgs)
if err != nil {
context.JSON(http.StatusBadRequest, gin.H{
"error": err.Error()})
return
}
1.8: バインディングヘッダー
type LoginJsonArgs struct {
Name string `header:"name" binding:"required"`
Password string `header:"password" binding:"required"`
}
var loginArgs LoginJsonArgs
err := context.ShouldBindHeader(&loginArgs)
if err != nil {
context.JSON(http.StatusBadRequest, gin.H{
"error": err.Error()})
return
}
1.9: Bind メソッドまたは ShouldBind メソッドを使用しますか?
- 違い: Bind がバインドに失敗した場合、応答ヘッダーに 400 ステータス コード情報が自動的に追加されます。
- レスポンスヘッダーのステータスコードではなく、ShouldBindを使用して、返されたレスポンス情報をもとにフロントエンドに判断させることを推奨します。
2: 応答
2.1: JSON データを返す
context.JSON(http.StatusOK, gin.H{
"status": "200", "msg": "login success"})
2.2: 戻り構造
package animal
import (
"github.com/gin-gonic/gin"
"net/http"
)
type LoginJsonArgs struct {
Name string `form:"name" binding:"required"`
Password string `form:"password" binding:"required"`
}
func testArgs(context *gin.Context) {
var loginArgs LoginJsonArgs
err := context.ShouldBindQuery(&loginArgs)
if err != nil {
context.JSON(http.StatusBadRequest, gin.H{
"error": err.Error()})
return
}
if loginArgs.Name != "root" && loginArgs.Password != "123456" {
context.JSON(http.StatusUnauthorized, gin.H{
"status": "401", "msg": "args validated fail"})
} else {
context.JSON(http.StatusOK, loginArgs)
}
}
2.3: protobuf に戻る
reps := []int64{
int64(1), int64(2)}
label := "resData"
resData := &protoexample.Test{
Label: &label,
Reps: reps,
}
context.ProtoBuf(200, resData)
2.4: リターンリダイレクト
context.Redirect(http.StatusMovedPermanently, "XXX地址")
3: 非同期コンテキスト
- 非同期リクエストでコンテキストを使用する場合は、コンテキストを再度コピーする必要があります。
package main
import (
"log"
"time"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
r.GET("/long_async", func(c *gin.Context) {
copyContext := c.Copy()
go func() {
time.Sleep(3 * time.Second)
log.Println("异步执行:" + copyContext.Request.URL.Path)
}()
})
r.Run(":8000")
}