Koa+React实现form表单上传文件
在nodejs里面通过html的表单上传图片,跟php比较起来还是麻烦一些,特别是在react中使用表单提交含有文件的数据。
最近也在做这个操作,找了很多资料,一直都是有个co-busboy这个,其实它也是基于busboy去封装的,不过这个更适合在koa里面使用。
以往的表单提交,我们用浏览器去debug的时候,会看到,提交了一个post提交的数据,这个一般只是值的提交,不包括有文件,但是在react中,
好像就更加复杂了一些,对于表单提交要单独自己写一个提交的事件去处理,累死submit这样的jquey函数。
而且提交成功后,我们用chrome去debug的时候,会发现提交的是一个Request Payload这样的,跟Form Data不一样,而且我们在koa中,
用body也是获取不到对应的值的,一切都是繁琐加着繁琐,自己考虑一下,像php这样的,是人家都帮你做好了,用起来很顺手,最终需要解决的就是,
如果把提交的data从header中去解析出来,其实busboy做的还是很好的。下面我大概说下我是如何去操作的。
web使用的jquery,通过FormData
在componentDidMount方法中初始化一下submit。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | let handleAction = this .props.handleAction; $( "#BackgroundForm" ).submit( function (e){ let formData = new FormData($( this )[ 0 ]); $.ajax({ url: '/theapp/upload/background' , data:formData, dataType: 'json' , type: 'post' , cache: false , contentType: false , processData: false , beforeSend: function (){ $( '#submitButton' ).attr( 'disabled' , true ); }, success: function (data){ if (data.success == true ){ handleAction( true ); $( '#errorContainer' ).html( '' ).hide(); } else if (data.success == false ){ let message = '<ul><li>' +data.message+ '!</li></ul>' ; $( '#errorContainer' ).html(message).show(); $( '#submitButton' ).attr( 'disabled' , false ); } },error: function (err){ console.log(err); } }); return false ; }); |
在server中的操作是这样的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 | const upload = function (ctx, key, streamName) { return new Promise( function (resolve, reject) { ctx.qiniuClient.upload(fs.createReadStream(streamName), key, function (err, result) { if (err) { return reject(err); } resolve(result); }); }); }; theapp.post( '/upload/background' , co.wrap( function *(ctx, next) { let parts = parse(ctx.req); let part; //初始化数据 let title = '' ; let theme = '' ; let theorder = '' ; let token = '' ; let big_url; let thumb_url; //获取form-data提交的数据 while (part = yield parts) { if ( Array .isArray(part)) { let name = part[ 0 ]; let value = part[ 1 ]; if (name == 'title' ) { title = value; } if (name == 'theme' ) { theme = value; } if (name == 'theorder' ) { theorder = value; } if (name == 'access_token' ) { token = value; } } else { let streamName = '/tmp/' + Math.random(); let stream = fs.createWriteStream(streamName); part.pipe(stream); if (part.fieldname == 'big_url' ) { big_url = streamName; } if (part.fieldname == 'thumb_url' ) { thumb_url = streamName; } } } if (!big_url) { throw new Error( '请上传背景大图' ); } if (!thumb_url) { throw new Error( '请上传背景小图' ); } if (!title) { fs.unlinkSync(big_url); fs.unlinkSync(thumb_url); throw new Error( '名称不能为空' ); } if (!theme) { fs.unlinkSync(big_url); fs.unlinkSync(thumb_url); throw new Error( '主题不能为空' ); } if (!theorder) { theorder = 0 ; } //名称判断存在 const url = ctx.config.hostDomain + '/admin/query' ; const sql = `SELECT * FROM qeeniao.app_dft_background WHERE title = '${title}' `; const options = { timeout: ctx.config.httpTimeout, method: 'POST' , data: { 'sql' : sql, 'access_token' : token} }; const requestData = yield urllib.request(url, options); let data = requestData.data.toString(); data = JSON.parse(data); if (data.length > 0 ) { fs.unlinkSync(big_url); fs.unlinkSync(thumb_url); throw new Error( '名称已经存在' ); } //上传图片 let big_res = yield upload(ctx, { 'key' : 'image/background/hd/' + title + '.jpg' }, big_url); big_url = big_res[ 'url' ]; let thumb_res = yield upload(ctx, { 'key' : 'image/background/thumbnail/' + title + '.jpg' }, thumb_url); thumb_url = thumb_res[ 'url' ]; //提交数据库 let postData = { 'title' : title, 'theme' : theme, 'theorder' : theorder, 'big_url' : big_url, 'thumb_url' : thumb_url, 'access_token' : token }; let postUrl = ctx.config.hostDomain + '/admin/add/background' ; let postoptions = { timeout: ctx.config.httpTimeout, method: 'POST' , data: postData }; let postRes = yield urllib.request(postUrl, postoptions); postRes = postRes.data.toString(); postRes = JSON.parse(postRes); ctx.body = postRes; })); |
这里使用了一个qn的库
在启动的时候我把他加入了context中
1 2 3 4 5 6 | app.context.qiniuClient = qn.create({ accessKey: "Your accessKey" , secretKey: "Your secretKey" , bucket: "Your bucket" , origin: 'Your origin' }); |
这样处理起来就没问题了,其实要是如果koa把busboy自己封装起来是最好的。
版权声明
由 durban创作并维护的 Gowhich博客采用创作共用保留署名-非商业-禁止演绎4.0国际许可证。
本文首发于
博客(
https://www.gowhich.com ),版权所有,侵权必究。
本文永久链接: https://www.gowhich.com/blog/727
版权声明
由 durban创作并维护的 Gowhich博客采用创作共用保留署名-非商业-禁止演绎4.0国际许可证。
本文首发于 Gowhich博客( https://www.gowhich.com ),版权所有,侵权必究。
本文永久链接: https://www.gowhich.com/blog/727