上传文件到 node 服务器

2019-02-27 by 杜宏伟

如果服务端是node提供服务,如何上传一个文件到服务器呢?

首先,建一个文件夹,里面放 index.html,index.js就可以了,index.js放服务端代码,index.html 放前端代码。

服务端

const koa = require('koa');
const app = new koa();
const koaBody = require('koa-body');
const fs = require('fs')
const send = require('koa-send')
app.use(koaBody({
  multipart: true,
  formidable: {
    maxFileSize: 200 * 1024 * 1024    // 设置上传文件大小最大限制,默认2M
  }
}));
app.use(async (ctx, next) => {
  if (ctx.path.endsWith('.html')) {
    await send(ctx, ctx.path);
  }
  else await next()
})
app.use(async (ctx) => {

  const file = ctx.request.files.file;    // 获取上传文件
  const reader = fs.createReadStream(file.path);    // 创建可读流
  const ext = file.name.split('.').pop();        // 获取上传文件扩展名
  const upStream = fs.createWriteStream(`upload/${Math.random().toString()}.${ext}`);        // 创建可写流
  reader.pipe(upStream);    // 可读流通过管道写入可写流
  return ctx.body = '上传成功';
})
app.listen(3000, () => {
  console.log('koa is listening in 3000');
})

用表单提交

name值是可以随便起的,不一定叫file,这个值对应服务端的 代码 ctx.request.files.file。服务端一次收到的可以是多个文件,用file这个key来取得对应的文件

<form action="http://localhost:3000" method="post" enctype="multipart/form-data">
    <input type="file" name="file" value="" />
    <input type="submit" value="提交" />
</form>

这种方式会刷新页面,如果不想影响本页面,可以做一个iframe提交

js方式提交

对于现在浏览器来说,用js方式提交或许是更好的方式,它带来最大的灵活度,而且代码也超简单。

function upload(e) {
      let file = document.getElementById('file1').files[0];
      var formData = new FormData();
      formData.append("file", file);
      let xhr = new XMLHttpRequest()
      xhr.open('post', 'http://localhost:3000')
      //xhr.setRequestHeader("Content-Type", "multipart/form-data")
      xhr.send(formData, false)
}
document.getElementById('btn1').onclick = upload

这里是放了一个btn,也可以直接监听file 的change事件。

看到我注释掉的那一行了吧,不要设定header,因为完整的header应该类型这样  Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryyWdrRqwCAQbZeoDD 但是boundary怎么得到?不知道。而且也不用我们算,XMLHttpRequest对象自动给我们算好了。

既然原生代码都不用设header,可以想的到,相关的库估计也不用设header,会自动识别 form-data

大文件需要切片,只需要知道一个函数即可 file.slice

canvas导出图片提交

canvas只能导出base64格式,可以直接把这个上传服务器,要是服务器不支持这个格式,又不想修改接口,前端可以把base64转成二进制,提交。不过呢,这种也会可能会有问题,因为是自己造的,和file表单控件中取出来的还是有很大差别的,自己查看一个file对象就知道了。所以最好还是服务端直接支持base64格式为好。

var data = canvas.toDataURL();
  // dataURL 的格式为 “data:image/png;base64,****”,逗号之前都是一些说明性的文字,我们只需要逗号之后的就行了
  data = data.split(',')[1];
  data = window.atob(data);
  var ia = new Uint8Array(data.length);
  for (var i = 0; i < data.length; i++) {
    ia[i] = data.charCodeAt(i);
  }

  // canvas.toDataURL 返回的默认格式就是 image/png
  var blob = new Blob([ia], { type: "image/png" })

  var formData = new FormData();
  formData.append("file", blob);
  return upload('/upload', formData)

下载

顺便说一下,如果要下载文件,只需要加一个头就可以了。浏览器看到这个头就知道不要在浏览器中显示,而是下载。

if (ctx.path.endsWith('.jpg')) {
    ctx.set('Content-Disposition', 'attachment')
    await send(ctx, ctx.path);
 }

我叫杜宏伟,前端开发。

一直想写博客,在2018的年的最后几天,终于上线了。

对于前端开发,一个特点就是太零散,很容易会了后面忘了前面,所以归纳总结很重要。再有就是分享,做前端好多年,以前都是看你们写的文章, 现在我也开始写一些,希望可以帮到入行的小伙伴。微信号 duhongwei5775

欢迎转载,只需注明作者,出处即可

版权说明:署名 4.0 国际(CC BY 4.0)