在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 問答/人工智能  HTML/ formidable上傳,第一張上傳成功,再上傳錯誤Can\'t set hea

formidable上傳,第一張上傳成功,再上傳錯誤Can\'t set headers after they are sent

用nodejs的formidable上傳圖片,第一張上傳成功,再上傳發(fā)生錯誤Can't set headers after they are sent

  • 1 錯誤表現(xiàn)

clipboard.png

圖上的結(jié)果是:我在mavoneditor編輯器里面上傳第一張圖片時,可以正確從服務(wù)端返回圖片的網(wǎng)絡(luò)地址,再上傳第二張圖片的時候,就報(bào)錯了,圖片地址任然是本地地址。

  • 2 服務(wù)端的報(bào)錯

clipboard.png

從信息上也看出我第一次post /upload 是成功的,前端也正確get 到了服務(wù)端圖片地址,第二次post卻發(fā)生錯誤了,錯誤信息 Can't set headers after they are sent

但第二次上傳的圖片卻已經(jīng)上傳到了服務(wù)端

clipboard.png

雖然從圖上看不出來,但upload里面的確多了一張圖片

  • 3 代碼

上傳圖片的前端代碼

<el-form-item label="商品詳情" prop="info">
     <mavon-editor  ref="md" @imgAdd="$imgAdd" @imgDel="$imgDel" v-model="addprod.info"></mavon-editor>
</el-form-item>

    // 圖片上傳并替換地址
    // 綁定@imgAdd event
    $imgAdd (pos, $file) {
      // 第一步.將圖片上傳到服務(wù)器.
      let formdata = new FormData()
      formdata.append('file', $file)
      // let uploadparams = {
      //   data: formdata,
      //   headers: { 'Content-Type': 'multipart/form-data' }
      // }
      // console.log('pos: ' + pos, formdata, $file)
      UploadFile(formdata)
      .then(url => {
        // console.log(url)
        console.log(this.addprod.info)
        // 第二步.將返回的url替換到文本原位置![...](./0) -> ![...](url)
        this.$refs.md.$img2Url(pos, url.data)
      })
    }
    
    
// 上傳圖片接口
export const UploadFile = params => {
  
  return axios({
    url: base + '/upload',
    method: 'post',
    headers: { 'Content-Type': 'multipart/form-data' },
    data: params
  })
}

服務(wù)端代碼


const {User, Product} = require('../models/model')
const formidable = require('formidable')
const form = new formidable.IncomingForm()
const path = require('path')
const fs = require('fs')

module.exports = {
  // 注冊
  regin: async (req, res, next) => {
    const newuser = new User(req.body)
    const adduser = await newuser.save()
    res.status(200).send({
      adduser: adduser
    })
  },
  // 登錄
  login: async (req, res, next) => {
    const user = await User.findOne(req.query)
    res.status(200).json({
      code: 200,
      msg: '登錄成功',
      user: user
    })
  },
  // 上傳圖片
  upload: (req, res, next) => {
    //上傳文件的保存路徑
    form.uploadDir = path.dirname('./upload/upload/')
    //保存擴(kuò)展名
    form.keepExtensions = true
    //上傳文件的最大大小
    form.maxFieldsSize = 20 * 1024 * 1024
    form.parse(req, (err, fields, files) => {
      
      // 項(xiàng)目未打包時使用
      const imagepath = 'http://localhost:8088/' + path.normalize(files.file.path)
      // 項(xiàng)目打包到server之后使用
      // const imagepath = path.normalize(files.file.path)
      res.status(200).send(imagepath)
      // return next()
    })
    
  },
  // 發(fā)送文件
  sendfile: (req, res, next) => {
    // console.log(req.params)
    const curfile = path.resolve(__dirname,'../upload/' + req.params.imagename)
    // console.log(curfile)
    res.status(200).sendFile(curfile)
    // return next()
  }
}

查了好多資料,大概知道這個錯誤是因?yàn)?我在發(fā)了一次http響應(yīng)頭之后又發(fā)了一次響應(yīng)頭,程序做出了重復(fù)響應(yīng),但我檢查了半天也沒發(fā)現(xiàn)哪里重復(fù)謝了多個res.xxx啊,其它寫return的辦法也試過,還是沒解決。

同時前端會有一個跨域代理的錯誤

[HPM] Error occurred while trying to proxy request //upload from localhost:8080 to http://localhost:8088 (ECONNRESET) (https://nodejs.org/api/errors...
_common_system_errors)

為了測試是否與跨域代理有關(guān)系,我將項(xiàng)目打包放到服務(wù)端測試,發(fā)現(xiàn)還是一樣的錯誤,再次求助各位幫忙看看解決,先謝過了!!

回答
編輯回答
孤巷

首先,解決問題

遇到類似問題,官方文檔往往是最好的解答。試下把你的代碼改成下面這樣,唯一的不同,就是把form的實(shí)例化挪動動 upload 里。

  // 上傳圖片
  upload: (req, res, next) => {

    const form = new formidable.IncomingForm() // 注意,把form 的實(shí)例化操作挪進(jìn)來

    //上傳文件的保存路徑
    form.uploadDir = path.dirname('./upload/upload/')
    //保存擴(kuò)展名
    form.keepExtensions = true
    //上傳文件的最大大小
    form.maxFieldsSize = 20 * 1024 * 1024
    form.parse(req, (err, fields, files) => {
      
      // 項(xiàng)目未打包時使用
      const imagepath = 'http://localhost:8088/' + path.normalize(files.file.path)
      // 項(xiàng)目打包到server之后使用
      // const imagepath = path.normalize(files.file.path)
      res.status(200).send(imagepath)
      // return next()
    })
    
  },

官方文檔在 這里,仔細(xì)看兩眼就會發(fā)現(xiàn)你的代碼跟它的差別。

其次,探究問題根源

如果好奇問題出在哪里,可以看下 formidable 的源碼,incoming_form.js

因?yàn)槟闼械?code>parse操作都是在同一個form實(shí)例上進(jìn)行,因此,this.on('end') 會被調(diào)用多次。

  1. 第一次上傳:注冊'end'回調(diào),假設(shè)回調(diào)為 cb1。文件上傳成功,cb1調(diào)用
  2. 第二次上傳:新增'end'回調(diào),假設(shè)回調(diào)為 cb2。由于 this.on() 注冊是累加的,當(dāng)前end事件的回調(diào)有兩個,cb1、cb2。文件上傳成功,cb1首先被調(diào)用,然后就悲劇了
IncomingForm.prototype.parse = function(req, cb) {

  // 忽略一堆無關(guān)緊要的代碼....

  // 注冊各種回調(diào),同樣忽略掉無關(guān)緊要的代碼
  if (cb) {
      this.on('end', function() {
        cb(null, fields, files);
      });
  }
2017年7月14日 13:41
編輯回答
風(fēng)畔

這個問題我之前也遇到過,所以你的代碼我沒有仔細(xì)看,有一個方法能避免這個錯誤,記得在每一次res后都要return關(guān)閉當(dāng)前的請求。

2018年7月14日 11:49