zoukankan      html  css  js  c++  java
  • 学习 Gin 问题总结 2020.12.29

    学习 Gin 问题总结 2020.12.29

    数据绑定与解析

    BindXXXShouldBindXXXShouldBindWith区别

    1. BindXXX

      会自动返回信息,输入无效时,在header写入400

    2. ShouldBindXXX

      返回消息,输入无效时,不会在header写入400状态码,这时候可以自定义返回信息,在使用上相对来说更加灵活。

    3. ShouldBindWith

      gin 1.4 之前,重复使用ShouldBind绑定会报错EOF

      gin 1.4 之后官方提供了一个 ShouldBindBodyWith 的方法,可以支持重复绑定,原理就是将body的数据缓存了下来,但是二次取数据的时候还是得用 ShouldBindBodyWith 才行,直接用 ShouldBind 还是会报错的。

      根据方法内参数b的类型去绑定jsonquery,去绑定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 statichtmlhtml2: 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,",
    "))
    }
    

    初始写法(错误):

    	go func() {
    			defer waitG.Done()
    			fmt.Println("正在保存",fileName[index])
    			cc.SaveUploadedFile(file,fileName[index])
    		}()
    	}
    

    错误原因总结:

    未进行传参,导致只有最后一个文件被上传,通过debug发现,虽然已经做同步处理(使用WaitGroup),但是goroutine内因为延迟求值的原因,导致每次都只是保存最后一个文件。传入参数fileNamefileUpload后,会立即复制参数,不会出现延迟求值的情况,使得保存文件按顺序进行保存。

  • 相关阅读:
    编译安装LEMP
    eAccelerator配置和使用指南
    /dev/null的用途
    分库分表
    JVM
    SOFA 数据透析
    HTTPS
    SOFA 通信
    分布式锁
    mysql 锁
  • 原文地址:https://www.cnblogs.com/l1ng14/p/14207911.html
Copyright © 2011-2022 走看看