vue3使用<input>上传图片,后端golang接收数据

641 阅读3分钟

前言

在做网页的时候需要用到图片上传,之前做图片上传时使用的时vant的组件,比较简单。直接传到后端一个base64的码,在后端解码然后返回给前端就好了,但是这次做图片上传不能用组件,要使用vue3自带的input来上传图片。然后,就开始了长达数小时的折磨,一个图片上传搞得我头都大了,幸而最后解决了问题,那么话不多说,开始吧。

前端vue3

<template>
  <input
    type="file"
    class="upload"
    @change="addImg"
    ref="inputer"
    accept="image/png,image/jpeg,image/gif,image/jpg"
  />
</template><script lang="ts">
import axios from "axios";
export default {
  setup() {
    function addImg(e) {
      const file = e.target.files[0]; //获得input上传的文件
      uploadImg(file); //将文件上传到后端的方法
    }
    //上传图片
    function uploadImg(img) {
      const formData = new FormData(); //使用formData上传文件
      formData.append("file", img);
      axios({
        method: "POST",
        url: "/api/user/info",
        headers: { "Content-Type": "multipart/form-data" },
        data: formData,
      }).then((res) => {
        console.log(res.data.md5);
      });
    }
    return {
      addImg,
      uploadImg,
    };
  },
};
</script>

前端的代码较为简单,主要注意的点就是fromData在传送时不要用花括号包裹 。如:

{data:fromData}

其次是注意传送时的headers,我们传送的是表单数据,如果在后端想以表单数据被接受,headers就要写成代码中的样子。

 headers: { "Content-Type": "multipart/form-data" }

在写这段代码时去网页上查看请求的负载,你可能会看到一个非常简洁的页面:

image.png

我一开始看到的时候认为是数据没有传送,但事实上是已经传送了的,至于为什么会这么“简洁”,暂时还未弄明白,而且关系不是很大。(强烈建议用火狐,火狐就没有这种情况)

前端就是这么简洁了,在我所写的代码中,后端在拿到前端送来的图片后,会下载图片然后把图片的名字(以MD5加密后的字符串)返还给前端,前端将此图片名与图片访问路径拼接后得到完整的图片路径(在这里我并没有这么做,但我会给出后端应如何加密及返回md5字符串)。

golang后端

后端要做的事情就有点多了,首先是提取前端的图片数据,然后是对数据进行md5加密,得到图片名,其后是创建文件并将文件名返回给前端。

import (
    "bufio"
    "crypto/md5"
    "encoding/hex"
    "encoding/json"
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
    "os"
)
​
type Message struct {
    Content []Content `json:"content"`
    Err     string    `json:"err"`
    Sign    int       `json:"sign"`
    MD5     string    `json:"md5"`
}
type Content struct {
    Cid     string `json:"cid"`
    Title   string `json:"title"`
    About   string `json:"about"`
    Content string `json:"content""`
}
​
func MD5(v interface{}) string {//获取md5字符串
    a := v.(string)
    d := []byte(a)
    m := md5.New()
    m.Write(d)
    return hex.EncodeToString(m.Sum(nil))
}
func Picture(w http.ResponseWriter, r *http.Request) {
    var a Message
    if err := r.ParseMultipartForm(r.ContentLength); err != nil {
        return
    }
    image := r.MultipartForm.File["file"][0] //获得文件数据,file为前端传送数据时自定义的键
    file, err := image.Open()
    if err == nil {
        data, err := ioutil.ReadAll(file) // 读取二进制文件字节流
        if err == nil {
            k := MD5(string(data)) //对图片进行md5加密(得到图片的名称)
            fmt.Println(k)
            name := fmt.Sprintf("%s%s", k, ".jpg") //生成图片名
            fmt.Println(name)
            dec := string(data)                         //将第i位置的字符到最后一个字符进行bas64解码,得到图片
            f, err := os.Create("./uploaded/a/" + name) //生成图片,记得创建文件夹
            if err != nil {
                log.Println(err)
            }
            defer f.Close()
            //写入文件时,使用带缓存的 *Writer
            write := bufio.NewWriter(f)
            write.WriteString(dec)
            //Flush将缓存的文件真正写入到文件中
            write.Flush()
            a.MD5 = name
            resp(w, &a) //发送图片名称给前端
        }
    }
}
func resp(w http.ResponseWriter, msg *Message) {
    if w == nil || msg == nil {
        fmt.Println("call respErr with invalid w/msg")
        return
    }
​
    //将msg结构体转化为json字符串
    buf, err := json.Marshal(&msg)
​
    if err != nil {
        w.Write([]byte(fmt.Sprintf(`{"code":-300,"msg":"%s"}`, err.Error())))
        fmt.Println(err.Error())
        return
    }
    //fmt.Println(buf)
    w.Write(buf)
}

golang的后端中提供了对fromData进行解析的方法,你可以使用

if err := r.ParseMultipartForm(r.ContentLength); err != nil {
        return
    }
image := r.MultipartForm.File["file"][0] //获得文件数据
file, err := image.Open()
data, err := ioutil.ReadAll(file) // 读取二进制文件字节流

来获取文件的二进制数据,也可以使用

if err := r.ParseMultipartForm(r.ContentLength); err != nil {
        return
    }
file, header, err := r.FormFile("file")
fmt.Println("FormFile(file):   ", file, header, err)

来获取文件,其效果是:

image.png

一样可以获得二进制字节,但是需要做一下字符匹配(大概?)

总结

图片上传暂时就到这吧,后面可能会优化一下上传及下载。