Golang File Upload

Golang 文件上传

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
g1 := r.Group("/api")
g1.Use(middlewares.JWTAuth(),cors.Default())
{
  g1.GET("/ping", func(c *gin.Context) {
    c.JSON(http.StatusOK,gin.H{"code":http.StatusOK,"message":"pong /api"})
  })
  g1.POST("/u", func(c *gin.Context) {
    log.Println("/u POST")
    form, err := c.MultipartForm()
    if err != nil {
      c.JSON(http.StatusOK, gin.H{"code":http.StatusBadRequest,"msg":fmt.Sprintf("error get form: %s",err.Error())})
      return
    }
    files := form.File["files"]

    for _, file := range files {
      basename := filepath.Base(file.Filename)
      filename := filepath.Join(".", basename)
      if err := c.SaveUploadedFile(file, filename); err != nil {
        c.JSON(http.StatusOK, gin.H{"code":http.StatusBadRequest,"error": err.Error()})
        return
      }
    }

    var filenames []string
    for _, file := range files {
      filenames = append(filenames, file.Filename)
    }
    c.JSON(http.StatusOK, gin.H{"code":http.StatusAccepted,"msg":"upload ok!","data": gin.H{"files":filenames}})
  })
}

可同时上传多个文件

分别使用Postman git bash里的curl Windows子系统里的curl 调用

Postman

key 的值对应 上面代码里的 files := form.File["files"] 这一段

Kali

1
2
3
4
5
6
7
curl \
--request POST \
--url http://localhost:1005/api/u \
--header 'token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ
9.eyJzZXNzaW9uSWQiOiI2Y2JlMmFlYS1lMTFiLTQzOTItYTI4NS05NTRkZDhmMTBkNzAiLCJ1c2VySWQiOiIwIiwiZXhwIjoxNTU5MjA4NjI2LCJpc3MiOiJsbGlueC5tZSIsIm5iZiI6MTU1OTIwN
DAyNn0.0nBvCIPHR9ro_hhxgvoy6uc7Q0ftS1d5D8PXDa3zU04' \
-F "files=@/mnt/c/Users/linx/Desktop/1.txt"

一开始的时候提示 setting file failed, 还以为是不支持中文啥的 后来发现子系统的路径是不一样的 (─.─|||

git bash

1
2
3
4
5
curl \
--request POST \
--url http://localhost:1005/api/u \
--header 'token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzZXNzaW9uSWQiOiI2Y2JlMmFlYS1lMTFiLTQzOTItYTI4NS05NTRkZDhmMTBkNzAiLCJ1c2VySWQiOiIwIiwiZXhwIjoxNTU5MjA4NjI2LCJpc3MiOiJsbGlueC5tZSIsIm5iZiI6MTU1OTIwNDAyNn0.0nBvCIPHR9ro_hhxgvoy6uc7Q0ftS1d5D8PXDa3zU04' \
-F "files=@C:/Users/linx/Desktop/1.txt"

  • --request选项可以用 -X代替
  • 而如果 url 放在最后, 就不用写 –url 了
  • --header则可以使用 -H
  • SaveUploadedFile的时候, 对应的目录必须事先创建好, 否则报错

Vue上传页面(el-upload)

加了本地存储来存储token

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
<template>
  <div>
    <el-button size="small" type="primary" @click="doAuth">认证</el-button>
    <el-upload
      class="upload-demo"
      ref="upload"
      action="/api/u"
      name="files"
      :multiple="true"
      :drag="true"
      :headers="uploadHeaders"
      :on-preview="handlePreview"
      :on-remove="handleRemove"
      :file-list="fileList"
      :auto-upload="false"
    >
      <el-button slot="trigger" size="small" type="primary">选取文件</el-button>
      <el-button style="margin-left: 10px;" size="small" type="success" @click="submitUpload">上传</el-button>
    </el-upload>
  </div>
</template>

<script>
export default {
  data() {
    return {
      fileList: [],
      uploadHeaders: {
        token: ""
      }
    };
  },
  methods: {

    submitUpload() {
       this.$refs.upload.submit();
    },
    handleRemove(file, fileList) {
      console.log(file, fileList);
      this.fileList = fileList;
    },
    handlePreview(file) {
      console.log(file);
    },
    doAuth() {
        var token = localStorage.getItem('token');
        console.log(token)
      this.$http.get("/index/",{headers:{'token' : token}}).then(
        function(res) {
          console.log(res);
          if (res.body.code == 201) {
            this.uploadHeaders.token = res.body.data.token;
            localStorage.setItem("token",this.uploadHeaders.token);
          } else if (res.body.code == 100) {
            this.uploadHeaders.token = token;
          }
          
        },
        function(err) {
          console.log(err);
        }
      );
    }
  }
};
</script>

  • form.File["files"]name="files" 这两个需要对应, 最终会体现在header里

  • 使用 :headers="uploadHeaders"

    1
    2
    3
    4
    5
    
    uploadHeaders: {
          token: ""
        }
    
    this.uploadHeaders.token = token;
    

    这样的方式来让上传组件带上咱自己的token

  • action="/api/u"this.$http.get("/index/",{headers:{'token' : token}})

    这种不需要带域名端口的方式需要在项目根目录下创建 vue.config.js, 内容如下

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    
    module.exports = {
      devServer: {
        proxy: {
          '/api': {
            target: 'http://localhost:1005/api', 
            ws: true,
            changeOrigin: true,
            pathRewrite: {
              '^/api': ''    
            }
          },
          '/index': {
            target: 'http://localhost:1005/index',   
            ws: true,
            changeOrigin: true,
            pathRewrite: {
              '^/index': '' 
            }
    
          }
        }
      }
    }
    

    或者 简单点

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    
    module.exports = {
      devServer: {
        proxy: {
          '/api': {
            target: 'http://localhost:1005',   //代理接口
            ws: true,
            changeOrigin: true
          },
          '/index': {
            target: 'http://localhost:1005',   //代理接口
            ws: true,
            changeOrigin: true
          }
        }
      }
    }
    

    这样的方式不仅让调用更简单, 同时还能跨域, 当然后端也要加一句 g1.Use(middlewares.JWTAuth(),cors.Default())

记录平时瞎折腾遇到的各种问题, 方便查找
使用 Hugo 构建
主题 Stack 3.29.0Jimmy 设计