文件上传

原生表单

前端

原生表单需要设置 3 个属性:

  • action属性,即提交地址;
  • method属性指定表单提交请求类型;
    • get
    • post
    • put
    • delete
    • ...
  • enctype属性指定表单提交内容类型;
    • application/x-www-form-urlencoded:默认值
    • multipart/form-data:适用于使用<input>标签上传文件
    • text/plain:文本类型

原生表单如果想要上传多个文件,需要多个<input>标签,且name属性唯一;否则使用自定义 formData的上传方式。

<form action="/submit" method="post" enctype="multipart/form-data">
  <label for="file">file:</label>
  <input type="file" id="file" name="file">
  <input type="submit" value="提交"></input>
</form>

后端

  • fileUpload:处理文件的中间件;
const express = require('express');
const path = require('path');
const fileUpload = require('express-fileupload');

const app = express();

app.use(fileUpload());

app.post('/submit', (req, res) => {
  for (const key in req.files) {
    req.files[key].mv(path.resolve(__dirname, 'upload', req.files[key].name));
  }
  res.send('ok');
});

app.listen('8080');

自定义 formData

前端

  • FormData:接口提供了一种表示表单数据的键值对 key/value 的构造方式;
    • 当请求头Content-typemultipart/form-data时,它会使用和表单一样的格式;
    • 该数据是可以被for...of遍历的;

注意此时不要显示将Content-type置为multipart/form-data,手动添加会缺少boundary属性,导致后端无法正常解析。

<label for="file"></label>
<input type="file" id="file" multiple onchange="handleFiles(this.files)" />
<button onclick="submit()">提交</button>
const formData = new FormData();

function handleFiles(files) {
  for (const file of files) {
    formData.set(file.name, file);
  }
}
function submit() {
  fetch('/submit', { body: formData, method: 'post' });
}

后端

与原生表单接收服务器一样

const express = require('express');
const path = require('path');
const fileUpload = require('express-fileupload');

const app = express();

app.use(fileUpload());

app.post('/submit', (req, res) => {
  for (const key in req.files) {
    req.files[key].mv(path.resolve(__dirname, 'upload', req.files[key].name));
  }
  res.send('ok');
});

app.listen('8080');

base64

前端

  • FileReader:可以读取FileBlob对象中的文件数据(注:File继承了Blob);
    • readAsDataURL方法:读取Blob数据转为base64,存保存在result属性中;
    • onload事件:读取完成时触发;
    • result属性:保存readAsDataURL方法读取的数据(数据格式:由文件类型 + base64 标识 + base64 数据 构成)

一个 ASCII 字符需要 8bit 来表示,一个 base64 字符需要 6bit 来表示;6 个 ASCII 字符就需要 8 个 base64 字符表示。在数据传输上来说是增加体积,所以一般不用 base64 来传较大体积的数据。

<label for="file"></label>
<input type="file" id="file" onchange="handleFiles(this.files)" />
<button onclick="submit()">提交</button>
const uploadData = [];

function handleFiles(files) {
  for (const file of files) {
    const fr = new FileReader();
    fr.onload = function () {
      uploadData.push({ name: file.name, data: this.result.split(';base64,')[1] });
    };
    fr.readAsDataURL(file);
  }
}
function submit() {
  fetch('/submitbase64', {
    body: JSON.stringify(uploadData),
    method: 'post',
    headers: {
      'Content-Type': 'application/json'
    }
  });
}

后端

const express = require('express');
const path = require('path');
const fs = require('fs');

const app = express();

app.use(express.json());

app.post('/submitbase64', (req, res) => {
  for (const data of req.body) {
    fs.writeFileSync(path.resolve(__dirname, 'upload', data.name), data.data, 'base64');
  }
  res.sendStatus(200);
});

app.listen('8080');

相关文章

根据官网 入门 express
java叫接口control什么的app.get.post等等都是请求方式我们可...
为了前端丢进去的时候可以直接判断中间件就是经过了这个就会...
Express 文件的上传和下载
运行命令下载app.js 增加中间件。
基本模板来的 后面用后就有什么加什么都行。