由于本篇的内容需要涉及到一些静态资源的加载(get方法中打开的html页面),所以我们先进行静态资源配置,这里主要使用LoadHTMLGlob 加载html模板文件,使用StaticFS方法css、js及上传的文件。具体如下:

1func setStaticFS(r *gin.Engine) {
2    r.LoadHTMLGlob("views/*")
3    r.StaticFS("/static", http.Dir("public/static"))
4    r.StaticFS("/upload", http.Dir("upload"))
5}

一、post请求的分类

常用请求Headers中Content-Type的类型有text/plain、text/html、application/json、application/x-www-form-urlencoded、application/xml和multipart/form-data等。具体如下:

1text/plain 纯文本
2text/html HTML文档
3application/json json格式数据
4application/x-www-form-urlencoded 使用HTTP的POST方法提交的表单
5application/xml xml格式数据
6application/form-data主要是用来上传文件

二、API分组

gin提供了分组功能,便于把一些功能模块集中到一起,通过同一请求的URL前缀进行处理,我们使用分组功能,先把框架写出来,再构建具体的函数,如下:

 1api := r.Group("/api")
 2{
 3    api.POST("/form_post", formPost)
 4    api.POST("/json_post", jsonPost)
 5    api.POST("/urlencoded_post", urlencodedPost)
 6    api.POST("/json_and_form_post", jsonAndFormPost)
 7    api.POST("/xml_post", xmlPost)
 8    api.POST("/file_upload", fileUpload)
 9    api.GET("/list", func(c *gin.Context) {
10        message := c.Query("message")
11        nick := c.DefaultQuery("nick", "anonymous")
12        c.JSON(http.StatusOK, gin.H{
13            "status":  "SUCCESS",
14            "message": message,
15            "nick":    nick,
16        })
17    })
18}

通过该操作,我们完成了api路由分组。

三、功能实现

1、form 表单提交

上面路由分组中的/api/form_post调用的是后面的formPost方法,我们通过如下代码实现该方法:

 1api.POST("/form_post", formPost)
 2// 表单提交
 3func formPost(c *gin.Context) {
 4    message := c.PostForm("message")
 5    nick := c.DefaultPostForm("nick", "anonymous") // 没有获取到nick值时给一个默认值
 6    log.Println(message, nick)
 7    c.JSON(http.StatusOK, gin.H{
 8        "status":  "SUCCESS",
 9        "message": message,
10        "nick":    nick,
11    })
12}

在html页面中我们可以按如下方式调用:

<pre data-language="HTML">```markup
<form method="post" action="/api/form_post" class="">
    <input type="text" name="message">
    <input type="text" name="nick">
    <button type="submit" class="">提交</button>
<input type="hidden" name="ak_bib" value=""><input type="hidden" name="ak_bfs" value="1669994514042"><input type="hidden" name="ak_bkpc" value="0"><input type="hidden" name="ak_bkp" value=""><input type="hidden" name="ak_bmc" value="1025;1091,1633;827,1943;122,17281;163,126719;93,441;141,725;100,564;114,340;111,17967;116,329;"><input type="hidden" name="ak_bmcc" value="11"><input type="hidden" name="ak_bmk" value=""><input type="hidden" name="ak_bck" value=""><input type="hidden" name="ak_bmmc" value="31"><input type="hidden" name="ak_btmc" value="0"><input type="hidden" name="ak_bsc" value="33"><input type="hidden" name="ak_bte" value=""><input type="hidden" name="ak_btec" value="0"><input type="hidden" name="ak_bmm" value="2476,543;265,468;836,118;1551,589;271,407;735,158;745,1004;1750,367;1033,1158;737,95;835,724;862,5778;73,1;342,110;147,1;622,12;264,5;266,5805;598,758;3696,6191;3060,728;898,604;284,1;1343,762;1017,592;494,71;790,613;353,731;2872,322;1845,1065;950,927;"></form>

#### 2、post json数据

jsonPost方法如下:

```go
type User struct {
    Name    string `json:"name" form:"name"`
    Message string `json:"message" form:"message"`
    Nick    string `json:"nick" form:"nick"`
}
func jsonPost(c *gin.Context) {
    var user User
    c.BindJSON(&user)
    log.Println(user.Name, user.Message, user.Nick)
    c.JSON(http.StatusOK, gin.H{
        "status":  "SUCCESS",
        "name":    user.Name,
        "message": user.Message,
        "nick":    user.Nick,
    })
}

能过js调用代码如下:

 1$('.json').on('click', function() {
 2    axios({
 3        method: 'post',
 4        url: '/api/json_post',
 5        headers: {
 6            'Content-Type': 'application/json'
 7        },
 8        data
 9    }).then(res => {
10        console.log(res.data)
11        $('.json-msg').text(`success  ${new Date()}`)
12    })
13})

3、post x-www-form-urlencoded数据

 1// application/x-www-form-urlencoded
 2func urlencodedPost(c *gin.Context) {
 3    name := c.Query("name")
 4    message := c.PostForm("message")
 5    nick := c.DefaultPostForm("nick", "1231412")
 6    log.Println(name, message, nick)
 7    c.JSON(http.StatusOK, gin.H{
 8        "status":  "SUCCESS",
 9        "name":    name,
10        "message": message,
11        "nick":    nick,
12    })
13}

JS调用如下:

1$('.urlencoded').on('click', function() {
2    var data = {}
3    var inputs = $('#form input')
4    for (let i = 0; i  {
5        console.log(res.data)
6        $('.urlencoded-msg').text(`success  ${new Date()}`)
7    })
8})

4、通过bind方法同时支持post和form-urlencoded

也存在一些情况,我们不知道post过来的数据类型,我们想要同时支持两者,可以使用gin中的bind方法,具体代码如下:

 1type User struct {
 2    Name    string `json:"name" form:"name"`
 3    Message string `json:"message" form:"message"`
 4    Nick    string `json:"nick" form:"nick"`
 5}
 6// application/json  application/x-www-form-urlencoded
 7func jsonAndFormPost(c *gin.Context) {
 8    var user User
 9    c.Bind(&user)
10    log.Println(user.Name, user.Message, user.Nick)
11    c.JSON(http.StatusOK, gin.H{
12        "status":  "SUCCESS",
13        "name":    user.Name,
14        "message": user.Message,
15        "nick":    user.Nick,
16    })
17}

可以看到上面的代码中,我们对结构体的定义同时指定了json 和 form。对应的js我们也需要进行修改判断,如下:

 1$('.jsonandform').on('click', function() {
 2    var data = {}
 3    var inputs = $('#form input')
 4    for (let i = 0; i  {
 5        console.log(res.data)
 6        $('.jsonandform-msg').text(`success application/json data,  ${new Date()}`)
 7    })
 8})
 9$('.jsonandform2').on('click', function() {
10    var data = {}
11    var inputs = $('#form input')
12    for (let i = 0; i  {
13        console.log(res.data)
14        $('.jsonandform-msg').text(`success application/x-www-form-urlencoded data${new Date()}`)
15    })
16})

5、post xml格式数据

 1type User struct {
 2    Name    string `json:"name" form:"name" xml:"name"`
 3    Message string `json:"message" form:"message" xml:"message"`
 4    Nick    string `json:"nick" form:"nick" xml:"nick"`
 5}
 6func xmlPost(c *gin.Context) {
 7    var user User
 8    c.Bind(&user)
 9    log.Println(user.Name, user.Message, user.Nick)
10    c.JSON(http.StatusOK, gin.H{
11        "status":  "SUCCESS",
12        "name":    user.Name,
13        "message": user.Message,
14        "nick":    user.Nick,
15    })
16}

js调用如下:

1$('.xml_post').on('click', function() {
2    var data = {}
3    var inputs = $('#form input')
4    for (let i = 0; i ${data.name}${data.message}${data.nick}`
5    })
6})

6、post multipart/form-data

gin实现文件上传代码如下:

 1func fileUpload(c *gin.Context) {
 2    filesUrl := make([]string, 0)
 3    form, err := c.MultipartForm()
 4    if err != nil {
 5        log.Println("postMultipleFile error: %s")
 6    }
 7    files := form.File["file"]
 8    _, err = os.Stat("upload")
 9    if err != nil {
10        os.Mkdir("upload", os.ModePerm)
11    }
12    for _, file := range files {
13        log.Println(file.Filename)
14        // Upload the file to specific dst.
15        if err = c.SaveUploadedFile(file, "upload/"+file.Filename); err != nil {
16            log.Println("SaveUploadedFile error: %s")
17            return
18        }
19        filesUrl = append(filesUrl, "upload/"+file.Filename)
20    }
21    c.JSON(http.StatusOK, gin.H{
22        "state": "SUCCESS",
23        "url":   strings.Join(filesUrl, ";"),
24    })
25}

html实现:

<pre data-language="HTML">```markup
<div>
    <form id="multipleForm">
        <input type="file" name="file" id="file" multiple="multiple" accept="image/*">
    </form>
    <button class="file_upload">上传文件</button>
</div>

js实现:

```javascript
$('.file_upload').on('click', function () {
    // 单个文件上传
    // var fd = new FormData()
    // var file = document.getElementById('file')
    // fd.append('file', file.files[0])
    axios({
        method: 'post',
        url: '/api/file_upload',
        headers: {
            'Content-Type': 'application/form-data'
        },
        // data:fd
        data: new FormData($('#multipleForm')[0])
    }).then(res => {
        console.log(res.data)
        const urls = res.data.url.split(';')
        let imgHtml = '';
        for(let i = 0; i `
        }
        $('.file_upload-msg').html(`success ${new Date()} 文件地址/${res.data.url} ${imgHtml}`)
    })
})

完整代码:https://github.com/361way/golang/tree/master/gin/gin_rotuer_web