koa2使用busboy上传图片失败?

新手上路,请多包涵

问题描述

前端采用ant的upload组件进行图片上传,后端采用koa2框架搭的服务,前端用nigix反向代理8000端口到3001端口,其他get,post请求正常。

在使用upload组件后返回的request请求状态为200,但是后端没有成功生成图片。


upload组件方法

<Upload
       name="file"
       action="http://localhost:8000/api/goods/imgUpload"
       accept="image/*"
       data={(file)=>{this.upload(file)}}
       withCredentials
       listType="picture-card"
       fileList={fileList}
       onPreview={this.handlePreview}
       onChange={this.handleChange}
 >
      {fileList.length >= 10 ? null : uploadButton}
</Upload>

Requset Header格式如下

Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Connection: keep-alive
Content-Length: 814
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryZvGXdj5g8yvDOCFD
Cookie: USER_SID=qIk6gw9xjGBH4dnZSiID6ay4H7fMzyzA
Host: localhost:8000
Origin: http://localhost:8000
Referer: http://localhost:8000/
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36
X-Requested-With: XMLHttpRequest

Requset payload格式如下

------WebKitFormBoundaryZvGXdj5g8yvDOCFD
Content-Disposition: form-data; name="file"; filename="jiekuan_beika.png"
Content-Type: image/png

------WebKitFormBoundaryZvGXdj5g8yvDOCFD--

koa2 app.js文件如下

require("babel-register");
require("babel-polyfill");

const path = require('path')
const Koa = require('koa')
const convert = require('koa-convert')
const views = require('koa-views')
const koaStatic = require('koa-static')
const bodyParser = require('koa-bodyparser')
const koaLogger = require('koa-logger')
const session = require('koa-session-minimal')
const MysqlStore = require('koa-mysql-session')
const json = require('koa-json')
const koaBody = require('koa-body');


const errorHandle = require('./controllers/error-catch')
const config = require('./../config')
const routers = require('./routers/index')

const app = new Koa()

// session存储配置
const sessionMysqlConfig = {
  user: config.database.USERNAME,
  password: config.database.PASSWORD,
  database: config.database.DATABASE,
  host: config.database.HOST,
}
//配置错误处理中间件
app.use(errorHandle())
// 配置session中间件
const THIRTY_MINTUES = 30 * 60 * 1000;
const staticPath = "static";
app.use(session({
  key: 'USER_SID',
  store: new MysqlStore(sessionMysqlConfig),
  cookie: {
    maxAge: THIRTY_MINTUES,
    overwrite: false,
    rolling: true, //每次api请求是否重置session有效期 默认为fale
    renew: false,
  }
}))

app.use(koaStatic(
  path.join( __dirname,  staticPath)
))

// 配置控制台日志中间件
app.use(koaLogger())

// 配置ctx.body解析中间件
app.use(bodyParser(
  {
    enableTypes: ['json', 'form', 'text']
  }
))

//配置json解析中间件
app.use(json())

// 初始化路由中间件
app.use(routers.routes()).use(routers.allowedMethods())

// 监听启动端口
app.listen(config.port)
console.log(`the server is start at port ${config.port}`)

后台接收接口 格式如下

router.post('/goods/imgUpload',goodsController.imgUpload )

imgUpload 方法

    async imgUpload(ctx, next) {
        let result = new WebResult(ctx.request);

        let response = await uploadFile(ctx);

        if(response.success){
            result.set(1,'调用成功')
        }
        ctx.body = response
    }

uploadFile 方法

const inspect = require('util').inspect
const path = require('path')
const os = require('os')
const fs = require('fs')
const UtilType = require('./type')
const UtilDatetime = require('./datetime')
const Busboy = require('busboy')
import Appconfig from '../appConfig'

/**
 * 同步创建文件目录
 * @param  {string} dirname 目录绝对地址
 * @return {boolean}        创建目录结果
 */
function mkdirsSync(dirname) {
  if (fs.existsSync(dirname)) {
    return true
  } else {
    if (mkdirsSync(path.dirname(dirname))) {
      fs.mkdirSync(dirname)
      return true
    }
  }
}

/**
 * 获取上传文件的后缀名
 * @param  {string} fileName 获取上传文件的后缀名
 * @return {string}          文件后缀名
 */
function getSuffixName(fileName) {
  let nameList = fileName.split('.')
  return nameList[nameList.length - 1]
}

/**
 * 上传文件
 * @param  {object} ctx     koa上下文
 * @param  {object} options 文件上传参数 fileType文件类型, path文件存放路径
 * @return {promise}         
 */
function uploadFile(ctx) {
  let req = ctx.req
  let res = ctx.res

  
  //请求体格式不对 直接返回
  if (!/multipart\/form-data/i.test(req.headers['content-type'])) {
    return
  }
  let busboy = new Busboy({headers: req.headers})
  // 获取类型
  let fileType = 'upload'
  //创建路径
  let filePath = path.join(
    __dirname,
    '/../static/',
    fileType,
    UtilDatetime.parseStampToFormat(null, 'YYYY/MM/DD')
  )
  let mkdirResult = mkdirsSync(filePath)
  console.log('正在准备上传文件...')
  return new Promise((resolve, reject) => {

    let result = {
      code: -1,
      success: false,
      message: '',
      data: null,
    }
    console.log(busboy)
    // 解析请求文件事件
    busboy.on('file', function (fieldname, file, filename, encoding, mimetype) {
      console.log('文件上传中...')
      let fileName = Math.random().toString(16).substr(2) + '.' + getSuffixName(filename)
      let _uploadFilePath = path.join(filePath, fileName)
      let saveTo = path.join(_uploadFilePath)

      // 文件保存到制定路径
      file.pipe(fs.createWriteStream(saveTo))

      // 文件写入事件结束
      file.on('end', function () {
        result.success = true
        result.message = '文件上传成功'
        result.data = {
          pictureUrl: `//${ctx.host}/upload/${fileType}/${fileName}`
        }
        console.log('文件上传成功!')
        resolve(result)
      })
    })
    // 解析表单中其他字段信息
    busboy.on('field', function (fieldname, val, fieldnameTruncated, valTruncated, encoding, mimetype) {
      console.log('表单字段数据 [' + fieldname + ']: value: ' + inspect(val));
      result.data[fieldname] = inspect(val);
    });

    // 解析结束事件
    busboy.on('finish', function () {
      console.log('文件上传结束')
      result.message = "文件上传结束"
      resolve(result)
    })

    // 解析错误事件
    busboy.on('error', function (err) {
      console.log('文件上出错')
      reject(result)
    })
    //将流链接到busboy对象
    req.pipe(busboy);
  })
}


module.exports = {
  uploadFile
}

浏览busboy官方文档和github上发现uploadFile方法是和官方一致的,但是实际操作过程中,只会触发busboy.on('finish')方法,表示文件已经上传结束,但是busboy.on('file')方法并不会触发,也就是实际没有把选择的文件上传到本地服务器,研究了几天了,还是没有头绪,希望有人能够帮助我,谢谢。

阅读 3.8k
3 个回答

该问题解决了么? 我也遇到同样问题

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题