上传文件简单实现

依赖模块

安装依赖

  1. npm install --save busboy
  • busboy 是用来解析出请求中文件流

例子源码

demo源码

https://github.com/ChenShenhai/koa2-note/blob/master/demo/upload/

封装上传文件到写入服务的方法

  1. const inspect = require('util').inspect
  2. const path = require('path')
  3. const os = require('os')
  4. const fs = require('fs')
  5. const Busboy = require('busboy')
  6. /**
  7. * 同步创建文件目录
  8. * @param {string} dirname 目录绝对地址
  9. * @return {boolean} 创建目录结果
  10. */
  11. function mkdirsSync( dirname ) {
  12. if (fs.existsSync( dirname )) {
  13. return true
  14. } else {
  15. if (mkdirsSync( path.dirname(dirname)) ) {
  16. fs.mkdirSync( dirname )
  17. return true
  18. }
  19. }
  20. }
  21. /**
  22. * 获取上传文件的后缀名
  23. * @param {string} fileName 获取上传文件的后缀名
  24. * @return {string} 文件后缀名
  25. */
  26. function getSuffixName( fileName ) {
  27. let nameList = fileName.split('.')
  28. return nameList[nameList.length - 1]
  29. }
  30. /**
  31. * 上传文件
  32. * @param {object} ctx koa上下文
  33. * @param {object} options 文件上传参数 fileType文件类型, path文件存放路径
  34. * @return {promise}
  35. */
  36. function uploadFile( ctx, options) {
  37. let req = ctx.req
  38. let res = ctx.res
  39. let busboy = new Busboy({headers: req.headers})
  40. // 获取类型
  41. let fileType = options.fileType || 'common'
  42. let filePath = path.join( options.path, fileType)
  43. let mkdirResult = mkdirsSync( filePath )
  44. return new Promise((resolve, reject) => {
  45. console.log('文件上传中...')
  46. let result = {
  47. success: false,
  48. formData: {},
  49. }
  50. // 解析请求文件事件
  51. busboy.on('file', function(fieldname, file, filename, encoding, mimetype) {
  52. let fileName = Math.random().toString(16).substr(2) + '.' + getSuffixName(filename)
  53. let _uploadFilePath = path.join( filePath, fileName )
  54. let saveTo = path.join(_uploadFilePath)
  55. // 文件保存到制定路径
  56. file.pipe(fs.createWriteStream(saveTo))
  57. // 文件写入事件结束
  58. file.on('end', function() {
  59. result.success = true
  60. result.message = '文件上传成功'
  61. console.log('文件上传成功!')
  62. resolve(result)
  63. })
  64. })
  65. // 解析表单中其他字段信息
  66. busboy.on('field', function(fieldname, val, fieldnameTruncated, valTruncated, encoding, mimetype) {
  67. console.log('表单字段数据 [' + fieldname + ']: value: ' + inspect(val));
  68. result.formData[fieldname] = inspect(val);
  69. });
  70. // 解析结束事件
  71. busboy.on('finish', function( ) {
  72. console.log('文件上结束')
  73. resolve(result)
  74. })
  75. // 解析错误事件
  76. busboy.on('error', function(err) {
  77. console.log('文件上出错')
  78. reject(result)
  79. })
  80. req.pipe(busboy)
  81. })
  82. }
  83. module.exports = {
  84. uploadFile
  85. }

入口文件

  1. const Koa = require('koa')
  2. const path = require('path')
  3. const app = new Koa()
  4. // const bodyParser = require('koa-bodyparser')
  5. const { uploadFile } = require('./util/upload')
  6. // app.use(bodyParser())
  7. app.use( async ( ctx ) => {
  8. if ( ctx.url === '/' && ctx.method === 'GET' ) {
  9. // 当GET请求时候返回表单页面
  10. let html = `
  11. <h1>koa2 upload demo</h1>
  12. <form method="POST" action="/upload.json" enctype="multipart/form-data">
  13. <p>file upload</p>
  14. <span>picName:</span><input name="picName" type="text" /><br/>
  15. <input name="file" type="file" /><br/><br/>
  16. <button type="submit">submit</button>
  17. </form>
  18. `
  19. ctx.body = html
  20. } else if ( ctx.url === '/upload.json' && ctx.method === 'POST' ) {
  21. // 上传文件请求处理
  22. let result = { success: false }
  23. let serverFilePath = path.join( __dirname, 'upload-files' )
  24. // 上传文件事件
  25. result = await uploadFile( ctx, {
  26. fileType: 'album', // common or album
  27. path: serverFilePath
  28. })
  29. ctx.body = result
  30. } else {
  31. // 其他请求显示404
  32. ctx.body = '<h1>404!!! o(╯□╰)o</h1>'
  33. }
  34. })
  35. app.listen(3000, () => {
  36. console.log('[demo] upload-simple is starting at port 3000')
  37. })

运行结果

upload-simple-result

upload-simple-result

upload-simple-result

upload-simple-result