Skip to content

Commit 1784b28

Browse files
author
pedro
committed
feat:修复文件上传的大小缺失bug
1 parent cc98187 commit 1784b28

3 files changed

Lines changed: 63 additions & 52 deletions

File tree

lib/extend.ts

Lines changed: 57 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,8 @@ import {
99
} from './exception';
1010
import { toLine, unsets } from './util';
1111
import { 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';
1514
import { extname } from 'path';
1615

1716
import { Logger } from 'egg-logger';
@@ -125,7 +124,6 @@ export const logging = (app: Application) => {
125124
};
126125

127126
export 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
};

lib/file.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ export class Uploader {
2020
this.storeDir = storeDir;
2121
}
2222
/**
23-
* 处理文件流Stream
23+
* 处理文件对象
24+
* { size, encoding, fieldname, filename, mimeType, data }
2425
*/
2526
public async upload(files: any[]) {
2627
throw new Error('you must overload this method');
@@ -79,8 +80,8 @@ export class Uploader {
7980
/**
8081
* 生成图片的md5
8182
*/
82-
public generateMd5(data: any) {
83-
const buf = data._readableState.buffer.head.data;
83+
public generateMd5(item: any) {
84+
const buf = item.data;
8485
const md5 = crypto.createHash('md5');
8586
return md5.update(buf).digest('hex');
8687
}

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "lin-mizar",
3-
"version": "0.1.0-beta.2",
3+
"version": "0.1.0-beta.3",
44
"description": "The core library of Lin CMS",
55
"main": "lin/index.js",
66
"scripts": {
@@ -16,8 +16,8 @@
1616
"author": "pedrogao",
1717
"license": "MIT",
1818
"dependencies": {
19+
"async-busboy": "^0.7.0",
1920
"class-validator": "^0.9.1",
20-
"co-busboy": "^1.4.0",
2121
"consola": "^2.5.6",
2222
"dayjs": "^1.8.9",
2323
"egg-logger": "^2.4.1",

0 commit comments

Comments
 (0)