學習 Gin 問題總結 2020.12.29
數據綁定與解析
BindXXX,ShouldBindXXX和ShouldBindWith區別
-
BindXXX會自動返回信息,輸入無效時,在
header寫入400。 -
ShouldBindXXX返回消息,輸入無效時,不會在
header寫入400狀態碼,這時候可以自定義返回信息,在使用上相對來說更加靈活。 -
ShouldBindWith在
gin1.4 之前,重復使用ShouldBind綁定會報錯EOF。gin1.4 之后官方提供了一個ShouldBindBodyWith的方法,可以支持重復綁定,原理就是將body的數據緩存了下來,但是二次取數據的時候還是得用ShouldBindBodyWith才行,直接用ShouldBind還是會報錯的。根據方法內參數
b的類型去綁定json,query,去綁定obj,不返回狀態碼。
func (c *Context) ShouldBindWith(obj interface{}, b binding.Binding) error {
return b.Bind(c.Request, obj)
}
HTML渲染
func main() {
// 1.創建路由
r := gin.Default()
//靜態文件,聲明模板文件所在的目錄,系統自動解析
r.LoadHTMLGlob("static/html/*")
...
}
LoadHTMLGlob(),該方法參數內的目錄下,不能有二級目錄,存在二級目錄將會panic。
而且該方法只能在一個實例中對一個目錄使用一次(使用過的目錄下的子目錄同樣是為已使用)。
使用兩次
//靜態文件,聲明模板文件所在的目錄,系統自動解析
r.LoadHTMLGlob("static/html/*")
r.LoadHTMLGlob("static/html/html2/*")
將會:
panic: read static\html\html2: The handle is invalid.
如果需要解析兩個目錄下的HTML文件,可在同一目錄下創建兩個文件夾:
//靜態文件,聲明模板文件所在的目錄,系統自動解析
r.LoadHTMLGlob("static/html/*")
r.LoadHTMLGlob("static/html2/*")
[GIN-debug] Loaded HTML Templates (4):
- form.html
- login.html
- upload.html
-[GIN-debug] Loaded HTML Templates (2):
- uploadMore.html
-
此時將會正常解析兩個目錄下的HTML模板。
還可以使用:
//靜態文件,聲明模板文件所在的目錄,系統自動解析
r.LoadHTMLGlob("static/**/*")
-[GIN-debug] Loaded HTML Templates (5):
- form.html - login.html - upload.html - uploadMore.html
static目錄下的子目錄內的所有模板文件都將被解析。
注意:static目錄下的模板文件將不會被解析。
重定向
c.Redirect(http.StatusPermanentRedirect,"http://localhost:8080/updateBook")
狀態碼可選:
http.StatusPermanentRedirect //永久性重定向
http.StatusTemporaryRedirect //臨時性重定向
第二個參數為重定向的地址。
異步處理
// Async 異步處理,保存上傳文件,開啟相應數量的 goroutine
func Async(c *gin.Context) {
form, err := c.MultipartForm()
if err != nil {
c.String(http.StatusBadRequest,fmt.Sprintf("get err %s",err.Error()))
}
//根據key:‘files’,獲取表單中的文件切片
files := form.File["files"]
fileSum := len(files)
fileName := make([]string,fileSum)
//控制上傳文件同步問題處理
waitG := sync.WaitGroup{}
waitG.Add(fileSum)
for index, file := range files {
fileName[index] = file.Filename
//異步處理時,上下文應該復制一個只讀副本,不直接使用原始上下文
cc := c.Copy()
go func(c *gin.Context,fileName string,fileUpload *multipart.FileHeader) {
defer waitG.Done()
fmt.Println("正在保存",fileName)
cc.SaveUploadedFile(fileUpload,fileName)
}(cc,fileName[index],file)
}
waitG.Wait()
c.String(http.StatusOK,"%s",strings.Join(fileName,",\n"))
}
初始寫法(錯誤):
go func() {
defer waitG.Done()
fmt.Println("正在保存",fileName[index])
cc.SaveUploadedFile(file,fileName[index])
}()
}
錯誤原因總結:
未進行傳參,導致只有最后一個文件被上傳,通過debug發現,雖然已經做同步處理(使用WaitGroup),但是goroutine內因為延遲求值的原因,導致每次都只是保存最后一個文件。傳入參數fileName、fileUpload后,會立即復制參數,不會出現延遲求值的情況,使得保存文件按順序進行保存。
