1. 阶段一 上传图片 base64

之前使用读取图片 base64 位码的形式做图片上传。前端将图片转为 base64,后端再做解析上传。

1
2
3
4
5
<input
type="file"
accept="{this.state.inputAccept}"
onChange="{this.uploadImg}"
/>
1
2
3
4
5
6
7
8
9
10
uploadImg = (event) => {
const file = event.target.files[0];
const reader = new FileReader();
//将本地图片转为base 64
reader.readAsDataURL(file);
reader.onload = (e) => {
// 图片的base64
console.log(e.target.result);
};
};

2. 阶段二 通过 formData 上传

但是 base64 有一个明显的问题就是增加了传输体的大小。想起之前做过图片上传七牛云使用的 formData,

1
2
3
4
5
6
7
8
9
10
11
uploadImg = (event) => {
const file = event.target.files[0];
let formData = new FormData();
formData.append("file", file);
formData.append("key", key); // 随机key
formData.append("token", token); //上传七牛云的token
axios.post("xxx", formData, (res) => {
//上传成功后的结果,包括上传图片后图片的路径
console.log(res);
});
};

formData 相关的文档:https://developer.mozilla.org/zh-CN/docs/Web/API/FormData
image.png
简单理解,他一般用于 form 表单提交或者手动构建 key-value 键值对的形式上传 文件、图片、json 等数据。
比较尴尬的是,当我们在控制台手动打印 console.log(formData)会发现什么数据也没有

查阅文档发现 formData 是内部对象,不支持控制台答应,但是提供的 get/getAll API 可以使用,还有可以遍历 formData 的 entries 访问 formData 的属性

1
2
3
4
5
6
7
// 通过API
formData.get('key')
// 通过formData 的entries
for(let iteries of formData.entries()){
// key val
console.log(iteries[0],iteries[1])
}

后来和后端同学协调后做了图片上传阿里云(后端提供上传接口)

3. 阶段三 Content-Type 和请求体

已经得到了图片的 formData 但是发现仍然无法完成上传.

首先是上传的 request headers Content-Type 不符合规范,手动自定义 Content-Type 为 ‘multipart/form-data’后发现后端接口莫名的报错 404,改成其他形式的 Content-Type 没有问题,后来手动添加 boundary 就没有了后端接口的 404 报错。而  boundary 是浏览器默认加上的边界线(分割线),无需手动添加

image.png
而框架里封住的 axios 方法定义了默认的 Content-Type 并且对请求体做了数据处理。

image.png

深深的陷入这个坑很久,解决方法如下:

  1. 提交 formData 数据的时无需指定 Request Headers 的 Content-Type 类型(猜测:浏览器会添加 boundary 和发送的数据做边界区分)
  2. 封装的请求方法里不要对请求的数据做任何处理

正确的消息格式如下

image.png

嗯,好久没加班了,这个加班坑搞得还很难受。同时也反应出自己对一些基础知识的薄弱。

  1. 对 http 理解不够,Content-Type 各种类型对应的发送的文件类型
  2. 对 axios 的底层了解不深,仅仅停留在使用层面