Koa2 failed to upload pictures using busboy?

problem description

the front end uses the upload component of ant to upload images, the back end uses the service built by koa2 framework, and the front end uses nigix reverse proxy port 8000 to port 3001. Other get,post requests are normal.

the request request status returned after using the upload component is 200, but the backend does not successfully generate the picture.

< hr >

upload component method

<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>
< hr >

Requset Header format is as follows

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
< hr >

Requset payload format is as follows

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

------WebKitFormBoundaryZvGXdj5g8yvDOCFD--
< hr >

koa2 app.js file is as follows

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, //apisession 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}`)
< hr >

the format of the background receiving interface is as follows

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

imgUpload method

    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 method

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
}

browsing the official busboy documents and github found that the uploadFile method is consistent with the official, but in the actual operation, only the busboy.on ("finish") method will be triggered, indicating that the file has been uploaded, but the busboy.on (" file") method will not be triggered, that is, the selected file has not actually been uploaded to the local server. After several days of study, I still have no clue. I hope someone can help me. Thank you.


has the problem been solved? I also encountered the same problem


I am doing ueditor rich text editor image upload also encountered this problem, I do not know if it has been solved, hope the landlord to help


this problem solved? I have the same problem

Menu