Gin on the third day

1. Form parameters

Forms are transmitted as POST requests, and there are four common HTTP transmission formats:

  • application/json
  • application/x-www-form-urlencoded
  • application/xml
  • multipart/form-data

Form parameters can be obtained via the PostForm() method, which by default parses x-www-form-urlencoded or FROm-data format parameters

Let’s start by writing a simple submission form with a basic username and password

<! DOCTYPEhtml>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>demo1</title>
</head>
<body>
<form action="http://localhost:8080/form" method="post" action="application/x-www-form-urlencoded">User name:<input type="text" name="username" placeholder="Please enter your user name">  <br>&nbsp;&nbsp;&nbsp;Code:<input type="password" name="userpassword" placeholder="Please enter your password.">  <br>
    <input type="submit" value="Submit">
</form>
</body>
</html>
Copy the code

Here, the action of our form is set to post path later

package main

import (
   "fmt"
   "github.com/gin-gonic/gin"
   "net/http"
)

// Form parameters

func main(a){
   r:=gin.Default()
   r.POST("/form".func(c *gin.Context) {
      types:=c.DefaultPostForm("type"."post")
      // The key name corresponds to the HTML page attribute name
      username:=c.PostForm("username")
      password:=c.PostForm("userpassword")
      c.String(http.StatusOK,fmt.Sprintf("username:%s,password:%s,types:%s",username,password,types))
   })
   r.Run()
}
Copy the code

2. Upload files

2.1 Uploading a Single File

The multipart/form-data format is used for file uploading. Gin file uploading is similar to the native NET/HTTP method, except that GIN encapsulates the native request into C. Test. Again, start with an HTML page that uploads a single file

<! DOCTYPEhtml>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>demo2</title>
</head>
<body>
<form action="http://localhost:8080/upload" method="post" enctype="multipart/form-data">Uploading files:<input type="file" name="file" >
  <input type="submit" value="Submit">
</form>
</body>
</html>
Copy the code

The gin implementation then receives and saves the form file

package main

import (
   "github.com/gin-gonic/gin"
   "net/http"
)

// Upload a single file
func main(a){
   r:=gin.Default()
   / / 8 < < 20 8 * 2 ^ 20 = 8 m
   r.MaxMultipartMemory=8<<20
   r.POST("/upload".func(c *gin.Context){
      file,err:=c.FormFile("file")
      iferr! =nil{
         c.String(500."Error uploading file")
      }
      c.SaveUploadedFile(file,file.Filename)
      c.String(http.StatusOK,file.Filename+"Upload successful")
   })
   r.Run()
}
Copy the code

What if I want to limit uploads to PNG and no other file formats? We can implement functions that limit the type of file uploads ourselves

Select the file type from HEADERS and determine if it matches. The modified code looks like this

package main

import (
   "github.com/gin-gonic/gin"
   "net/http"
)

// Upload a single file

func main(a) {
   r := gin.Default()
   / / 8 < < 20 8 * 2 ^ 20 = 8 m
   r.MaxMultipartMemory = 8 << 20
   r.POST("/upload".func(c *gin.Context) {
      _,headers, err := c.Request.FormFile("file")
      iferr ! =nil {
         c.String(500."Error uploading file")}if headers.Header.Get("Content-Type")! ="image/png"{
         c.String(500."Upload PNG files only")
         return
      }
      c.SaveUploadedFile(headers, "./imgs/"+headers.Filename)
      c.String(http.StatusOK, headers.Filename+"Upload successful")
   })
   r.Run()
}
Copy the code

2.2 Uploading multiple Files

Multi-file upload means that you can upload multiple files at once, which makes it easier for the uploader. (Some websites can only upload one file at a time, which is really uncomfortable.)

There is no special change to the uploaded page, just add a multiple to the Input upload form

<! DOCTYPEhtml>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>demo2</title>
</head>
<body>
<form action="http://localhost:8080/upload" method="post" enctype="multipart/form-data">Uploading files:<input type="file" name="files" multiple>
  <input type="submit" value="Submit">
</form>
</body>
</html>
Copy the code

Mostly back-end operations, but luckily gin has a multipart form module (encapsulating mime/multipart, all parsed)

package main

import (
   "fmt"
   "github.com/gin-gonic/gin"
   "net/http"
)

// Multiple file uploads

func main(a) {
   r := gin.Default()
   r.MaxMultipartMemory = 8 << 20
   r.POST("/upload".func(c *gin.Context) {
      form, err := c.MultipartForm()
      iferr ! =nil {
         c.String(http.StatusBadRequest, fmt.Sprintf("get err %s"), err.Error())
      }
      files := form.File["files"]
      for _,file :=range files{
         if err:=c.SaveUploadedFile(file,"./res/"+file.Filename); err! =nil{
            c.String(http.StatusBadRequest,fmt.Sprintf("upload err %s",err.Error()))
            return
         }
      }
      c.String(http.StatusOK,fmt.Sprintf("upload %d files".len(files)))
   })

   r.Run()
}
Copy the code

3. 404 pages

Often when we’re developing, we don’t know what kind of URL the user is going to type in the future, so we need to set up 404 pages, which are pages that can’t be found, right

package main

import (
   "fmt"
   "github.com/gin-gonic/gin"
   "net/http"
)

// Set 404 NOT FOUND

func main(a){
   r:=gin.Default()
   r.GET("/user".func(c *gin.Context){
      name:=c.DefaultQuery("name"."shelgi")
      c.String(http.StatusOK,fmt.Sprintf("hello %s",name))
   })
   // When accessing an unknown route
   r.NoRoute(func(c *gin.Context){
      c.String(http.StatusNotFound,"404 NOT FOUND")
   })
   r.Run()
}
Copy the code

Let’s go to the routing interface we’ve set up

Try again the screen where no route is set

Look at the NoRoute ()

It’s a method of the engine that passes in a processor function that returns 404 by default

These processor functions are defined at the top

Looking at engines, blind guessing is a structure with many methods and properties

Sure enough, you guessed right. An engine is an instance of a framework that contains multiplexing routes, middleware, and Settings. You can create an engine instance using either New() or Default(). This is why we always start with gin-.default (), in other words we can use gin-.new () instead.

Learning about Gin

After three days of learning, Gin is not very difficult to learn according to my experience, but there are not enough relevant materials in the community or on the Internet. I have been exposed to GO before, and I have read basic classic books and web-related books, but I did not get involved in the specific framework. In order to really get to know Gin, I have reviewed the basic knowledge of GO again, which I think is very useful when I am learning Gin.

To learn Gin, we have to learn to read and understand the source code by ourselves, because of its few resources and the lack of detailed official documents. This is why my blog adds many source code explanations in addition to reproducing the contents of the documents, which also requires us to have a certain degree of mastery of GO. So the basic language knowledge needs to be stable before learning any framework (especially for me, who often uses many languages in a day, so I can keep my mind clear).

I will also continue to write the Gin column, trying to clarify some of the details, from implementation to source code parsing in the hope of helping later learners. In addition, I have my eye on GoFrame, an enterprise-level framework developed in China, and the official documentation is very rich. After Gin, I should start to use GoFrame, like Flask vs Django?