Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

multipart plugin for egg

License

NotificationsYou must be signed in to change notification settings

eggjs/multipart

Repository files navigation

NPM versionNode.js CITest coverageKnown Vulnerabilitiesnpm downloadPRs WelcomeCodeRabbit Pull Request Reviews

Useco-busboy to upload file by streaming andprocess it without save to disk(using thestream mode).

Just usectx.multipart() to got file stream, then pass to image processing module such asgm or upload to cloud storage such asoss.

Whitelist of file extensions

For security, if uploading file extension is not in white list, will response as400 Bad request.

Default Whitelist:

constwhitelist=[// images'.jpg','.jpeg',// image/jpeg'.png',// image/png, image/x-png'.gif',// image/gif'.bmp',// image/bmp'.wbmp',// image/vnd.wap.wbmp'.webp','.tif','.psd',// text'.svg','.js','.jsx','.json','.css','.less','.html','.htm','.xml',// tar'.zip','.gz','.tgz','.gzip',// video'.mp3','.mp4','.avi',];

fileSize

The default fileSize that multipart can accept is10mb. if you upload a large file, you should specify this config.

// config/config.default.jsexports.multipart={fileSize:'50mb',};

Custom Config

Developer can custom additional file extensions:

// config/config.default.jsexports.multipart={// will append to whilelistfileExtensions:['.foo','.apk',],};

Can alsooverride built-in whitelist, such as only allow png:

// config/config.default.jsexports.multipart={whitelist:['.png',],};

Or by function:

exports.multipart={whitelist:(filename)=>['.png'].includes(path.extname(filename)||'')};

Note: if definewhitelist, thenfileExtensions will be ignored.

Examples

More examples please follow:

file mode: the easy way

If you don't know theNode.js Stream work,maybe you should use thefile mode to get started.

The usage very similar tobodyParser.

  • ctx.request.body: Get all the multipart fields and values, exceptfile.
  • ctx.request.files: Contains allfile from the multipart request, it's an Array object.

WARNING: you should remove the temporary upload files after you use it,theasync ctx.cleanupRequestFiles() method will be very helpful.

Enablefile mode on config

You need to setconfig.multipart.mode = 'file' to enablefile mode:

// config/config.default.jsexports.multipart={mode:'file',};

Afterfile mode enable, egg will remove the old temporary files(don't include today's files) on04:30 AM every day by default.

config.multipart={mode:'file',tmpdir:path.join(os.tmpdir(),'egg-multipart-tmp',appInfo.name),cleanSchedule:{// run tmpdir clean job on every day 04:30 am// cron style see https://github.com/eggjs/egg-schedule#cron-style-schedulingcron:'0 30 4 * * *',disable:false,},};

Default will use the last field which has same name, if need the all fields value, please setallowArrayField in config.

// config/config.default.jsexports.multipart={mode:'file',allowArrayField:true,};

Upload One File

<formmethod="POST"action="/upload?_csrf={{ ctx.csrf | safe }}"enctype="multipart/form-data">  title:<inputname="title"/>  file:<inputname="file"type="file"/><buttontype="submit">Upload</button></form>

Controller which hanlderPOST /upload:

// app/controller/upload.jsconstController=require('egg').Controller;constfs=require('mz/fs');module.exports=classextendsController{asyncupload(){const{ ctx}=this;constfile=ctx.request.files[0];constname='egg-multipart-test/'+path.basename(file.filename);letresult;try{// process file or upload to cloud storageresult=awaitctx.oss.put(name,file.filepath);}finally{// remove tmp files and don't block the request's response// cleanupRequestFiles won't throw error even remove file io error happenctx.cleanupRequestFiles();// remove tmp files before send response// await ctx.cleanupRequestFiles();}ctx.body={url:result.url,// get all field valuesrequestBody:ctx.request.body,};}};

Upload Multiple Files

<formmethod="POST"action="/upload?_csrf={{ ctx.csrf | safe }}"enctype="multipart/form-data">  title:<inputname="title"/>  file1:<inputname="file1"type="file"/>  file2:<inputname="file2"type="file"/><buttontype="submit">Upload</button></form>

Controller which hanlderPOST /upload:

// app/controller/upload.jsconstController=require('egg').Controller;constfs=require('mz/fs');module.exports=classextendsController{asyncupload(){const{ ctx}=this;console.log(ctx.request.body);console.log('got %d files',ctx.request.files.length);for(constfileofctx.request.files){console.log('field: '+file.fieldname);console.log('filename: '+file.filename);console.log('encoding: '+file.encoding);console.log('mime: '+file.mime);console.log('tmp filepath: '+file.filepath);letresult;try{// process file or upload to cloud storageresult=awaitctx.oss.put('egg-multipart-test/'+file.filename,file.filepath);}finally{// remove tmp files and don't block the request's response// cleanupRequestFiles won't throw error even remove file io error happenctx.cleanupRequestFiles([file]);}console.log(result);}}};

stream mode: the hard way

If you're well-known about know the Node.js Stream work, you should use thestream mode.

Use withfor await...of

<formmethod="POST"action="/upload?_csrf={{ ctx.csrf | safe }}"enctype="multipart/form-data">  title:<inputname="title"/>  file1:<inputname="file1"type="file"/>  file2:<inputname="file2"type="file"/><buttontype="submit">Upload</button></form>

Controller which hanlderPOST /upload:

// app/controller/upload.jsconst{ Controller}=require('egg');constfs=require('fs');conststream=require('stream');constutil=require('util');const{ randomUUID}=require('crypto');constpipeline=util.promisify(stream.pipeline);module.exports=classUploadControllerextendsController{asyncupload(){constparts=this.ctx.multipart();constfields={};constfiles={};forawait(constpartofparts){if(Array.isArray(part)){// fieldsconsole.log('field: '+part[0]);console.log('value: '+part[1]);}else{// otherwise, it's a streamconst{ filename, fieldname, encoding, mime}=part;console.log('field: '+fieldname);console.log('filename: '+filename);console.log('encoding: '+encoding);console.log('mime: '+mime);// how to handler?// 1. save to tmpdir with pipeline// 2. or send to oss// 3. or just consume it with another for await// WARNING: You should almost never use the origin filename as it could contain malicious input.consttargetPath=path.join(os.tmpdir(),randomUUID()+path.extname(filename));awaitpipeline(part,createWriteStream(targetPath));// use `pipeline` not `pipe`}}this.ctx.body='ok';}};

Upload One File (DEPRECATED)

You can got upload stream byctx.getFileStream*().

<formmethod="POST"action="/upload?_csrf={{ ctx.csrf | safe }}"enctype="multipart/form-data">  title:<inputname="title"/>  file:<inputname="file"type="file"/><buttontype="submit">Upload</button></form>

Controller which handlerPOST /upload:

// app/controller/upload.jsconstpath=require('node:path');const{ sendToWormhole}=require('stream-wormhole');const{ Controller}=require('egg');module.exports=classextendsController{asyncupload(){const{ ctx}=this;// file not exists will response 400 errorconststream=awaitctx.getFileStream();constname='egg-multipart-test/'+path.basename(stream.filename);// process file or upload to cloud storageconstresult=awaitctx.oss.put(name,stream);ctx.body={url:result.url,// process form fields by `stream.fields`fields:stream.fields,};}asyncuploadNotRequiredFile(){const{ ctx}=this;// file not requiredconststream=awaitctx.getFileStream({requireFile:false});letresult;if(stream.filename){constname='egg-multipart-test/'+path.basename(stream.filename);// process file or upload to cloud storageconstresult=awaitctx.oss.put(name,stream);}else{// must consume the empty streamawaitsendToWormhole(stream);}ctx.body={url:result&&result.url,// process form fields by `stream.fields`fields:stream.fields,};}};

Upload Multiple Files (DEPRECATED)

<formmethod="POST"action="/upload?_csrf={{ ctx.csrf | safe }}"enctype="multipart/form-data">  title:<inputname="title"/>  file1:<inputname="file1"type="file"/>  file2:<inputname="file2"type="file"/><buttontype="submit">Upload</button></form>

Controller which hanlderPOST /upload:

// app/controller/upload.jsconstController=require('egg').Controller;module.exports=classextendsController{asyncupload(){const{ ctx}=this;constparts=ctx.multipart();letpart;while((part=awaitparts())!=null){if(part.length){// arrays are busboy fieldsconsole.log('field: '+part[0]);console.log('value: '+part[1]);console.log('valueTruncated: '+part[2]);console.log('fieldnameTruncated: '+part[3]);}else{if(!part.filename){// user click `upload` before choose a file,// `part` will be file stream, but `part.filename` is empty// must handler this, such as log error.continue;}// otherwise, it's a streamconsole.log('field: '+part.fieldname);console.log('filename: '+part.filename);console.log('encoding: '+part.encoding);console.log('mime: '+part.mime);constresult=awaitctx.oss.put('egg-multipart-test/'+part.filename,part);console.log(result);}}console.log('and we are done parsing the form!');}};

Supportfile andstream mode in the same time

If the defaultmode isstream, use thefileModeMatch options to match the request urls switch tofile mode.

config.multipart={mode:'stream',// let POST /upload_file request use the file mode, other requests use the stream mode.fileModeMatch:/^\/upload_file$/,// or glob// fileModeMatch: '/upload_file',};

NOTICE:fileModeMatch options only work onstream mode.

License

MIT

Contributors

Contributors

Made withcontributors-img.


[8]ページ先頭

©2009-2025 Movatter.jp