Skip to content

前端文件上传功能

Request headers(请求头信息)

Request headers 是客户端向服务端发送http请求的一部分,它包含了Content-Type这个字段,指定了客户端发送的内容类型。

请求头可能有这些值:

  • application/json:是JSON格式提交的方式,使用最广泛。
  • application/x-www-form-urlencoded :这是form表单提交的时候的表示方式。
  • multipart/form-data: 也是一个常见的POST数据提交的方式,一般是在使用表单上传文件时使用。

WARNING

当表单向服务器上传的内容包含文件时,使用multipart/form-data

html
<form action="" method="" id="formElem">
  <div class="form-item">
    <label for="name">name: </label>
    <input type="text" name="name" value="John">
  </div>
  <div class="form-item">
    <label for="avatar">avatar: </label>
    <input
      type="file"
      name="avatar"
      id="file"
      accept="image/*"
      required
    />
  </div>
  <div class="form-item">
    <input type="submit" value="提交" />
  </div>
</form>

使用XMLHttpRequest提交数据

js
const form = document.querySelector('#formElem')
form.onsubmit = async (e) => {
  e.preventDefault();
  const f = document.querySelector("#file").files;
  const formObj = new FormData();
  formObj.append("file", f[0]);

  const xhr = new XMLHttpRequest();
  xhr.open("POST", "http://localhost:3000/file/upload", true);
  xhr.setRequestHeader("Content-Type", "multipart/form-data");
  xhr.onload = function () {
    if (xhr.status == 200) {
      alert("uploaded!");
    }
  };
  xhr.send(f);
}

使用fetch提交数据

js
const form = document.querySelector('#formElem')
form.onsubmit = async (e) => {
  e.preventDefault();

  let response = await fetch('http://localhost:3000/file/upload', {
    method: 'POST',
    body: new FormData(form)
  });

  let result = await response.json();

  alert(result.message);
};

服务端处理表单数据

服务端使用Node.js处理,引入Multer,官方明确指出它可以处理的数据形式为 multipart/form-data

TIP

Multer is a node.js middleware for handling multipart/form-data, which is primarily used for uploading files. It is written on top of busboy for maximum efficiency.

js
import * as multer from 'multer';

const storage = multer.diskStorage({
  destination: function (req, file: any, cb) {
    let des = './uploads';
    if (file.mimetype.slice(0, 5) === 'image') des = './uploads/image';
    if (file.mimetype.slice(0, 5) === 'audio') des = './uploads/audio';
    if (file.mimetype.slice(0, 5) === 'video') des = './uploads/video';
    cb(null, des);
  },
  filename: function (req, file: any, cb) {
    const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1e9) + '.' + file.originalname.split('.').at(-1);
    cb(null, uniqueSuffix);
  },
});

它的disStorage接收的参数中可以获取到前端上传的file信息,可以根据这些信息进行文件分类,或者文件重新命名。

总结

有时候前端上传了文件但是服务端并没有解析到,可能是请求头Content-Type的问题。

Released under the MIT License.