99} from './exception' ;
1010import { toLine , unsets } from './util' ;
1111import { config } from './config' ;
12- import { get , set , cloneDeep } from 'lodash' ;
13- import parse from 'co-busboy' ;
14- import sendToWormhole from 'stream-wormhole' ;
12+ import { get , set } from 'lodash' ;
13+ import asyncBusboy from 'async-busboy' ;
1514import { extname } from 'path' ;
1615
1716import { Logger } from 'egg-logger' ;
@@ -125,7 +124,6 @@ export const logging = (app: Application) => {
125124} ;
126125
127126export interface MulOpts {
128- autoFields ?: boolean ;
129127 singleLimit ?: number ;
130128 totalLimit ?: number ;
131129 fileNums ?: number ;
@@ -143,51 +141,62 @@ export const multipart = (app: Application) => {
143141 if ( ! this . is ( 'multipart' ) ) {
144142 throw new Error ( 'Content-Type must be multipart/*' ) ;
145143 }
146- // field指表单中的非文件
147- const parts = parse ( this , { autoFields : opts && opts . autoFields } ) ;
148- let part ;
144+ let filePromises : Promise < any > [ ] = [ ] ;
145+ const { fields } = await asyncBusboy ( this . req , {
146+ onFile : async function ( fieldname , file , filename , encoding , mimetype ) {
147+ const filePromise = new Promise ( ( resolve , reject ) => {
148+ let bufs = [ ] ;
149+ file
150+ . on ( 'error' , err => {
151+ file . resume ( ) ;
152+ reject ( err ) ;
153+ } )
154+ . on ( 'data' , ( d : never ) => {
155+ bufs . push ( d ) ;
156+ } )
157+ . on ( 'end' , ( ) => {
158+ const buf = Buffer . concat ( bufs ) ;
159+ resolve ( {
160+ size : buf . length ,
161+ encoding : encoding ,
162+ fieldname : fieldname ,
163+ filename : filename ,
164+ mimeType : mimetype ,
165+ data : buf
166+ } ) ;
167+ } ) ;
168+ } ) ;
169+ filePromises . push ( filePromise ) ;
170+ }
171+ } ) ;
172+ let files : any [ ] = [ ] ;
149173 let totalSize = 0 ;
150- const files : any [ ] = [ ] ;
151- // tslint:disable-next-line:no-conditional-assignment
152- while ( ( part = await parts ( ) ) != null ) {
153- if ( part . length ) {
154- // arrays are busboy fields
155- } else {
156- if ( ! part . filename ) {
157- // user click `upload` before choose a file,
158- // `part` will be file stream, but `part.filename` is empty
159- // must handler this, such as log error.
160- await sendToWormhole ( part ) ;
161- continue ;
162- }
163- // otherwise, it's a stream
164- // part.fieldname, part.filename, part.encoding, part.mime
165- // _readableState.length
166- // part.readableLength 31492 检查单个文件的大小
167- // 超过长度,报错
168- // 检查extension,报错
169- const ext = extname ( part . filename ) ;
170- if (
171- ! checkFileExtension ( ext , opts && opts . include , opts && opts . exclude )
172- ) {
173- throw new FileExtensionException ( { msg : `不支持类型为${ ext } 的文件` } ) ;
174- }
175- const { valid, conf } = checkSingleFileSize (
176- part . _readableState . length ,
177- opts && opts . singleLimit
178- ) ;
179- if ( ! valid ) {
180- throw new FileTooLargeException ( {
181- msg : `文件单个大小不能超过${ conf } b`
182- } ) ;
183- }
184- // 计算总大小
185- totalSize += part . _readableState . length ;
186- const tmp = cloneDeep ( part ) ;
187- files . push ( tmp ) ;
188- // 恢复再次接受data
189- part . resume ( ) ;
174+
175+ for ( const filePromise of filePromises ) {
176+ let file ;
177+ try {
178+ file = await filePromise ;
179+ } catch ( error ) {
180+ throw new HttpException ( { msg : '文件体损坏,无法读取' } ) ;
181+ }
182+ const ext = extname ( file . filename ) ;
183+ if (
184+ ! checkFileExtension ( ext , opts && opts . include , opts && opts . exclude )
185+ ) {
186+ throw new FileExtensionException ( { msg : `不支持类型为${ ext } 的文件` } ) ;
187+ }
188+ const { valid, conf } = checkSingleFileSize (
189+ file . size ,
190+ opts && opts . singleLimit
191+ ) ;
192+ if ( ! valid ) {
193+ throw new FileTooLargeException ( {
194+ msg : `${ file . filename } 大小不能超过${ conf } 字节`
195+ } ) ;
190196 }
197+ // 计算总大小
198+ totalSize += file . size ;
199+ files . push ( file ) ;
191200 }
192201 const { valid, conf } = checkFileNums ( files . length , opts && opts . fileNums ) ;
193202 if ( ! valid ) {
@@ -200,6 +209,7 @@ export const multipart = (app: Application) => {
200209 if ( ! valid1 ) {
201210 throw new FileTooLargeException ( { msg : `总文件体积不能超过${ conf1 } ` } ) ;
202211 }
212+ this . request . fields = fields ;
203213 return files ;
204214 } ;
205215} ;
0 commit comments