前言
使用原生来写 POST 的处理, 比较复杂, 而且文件上传业务比较的难写, 所以肯定有人造好了相关的轮子, 也就是 Node.js 的第三方模块 formidable , 使用 formidable 当做中间件用来处理文件上传非常方便, 而且可以配合其他模块对文件进行相应的命名。
不过在对 formidable 学习过程中出现了一个问题, 就是上传文件时, form.parse() 回调函数中 files 对象是个空对象。 就排查了挺久, 然后就以为问题是出在服务器端的代码上, 百度上关于这个问题也是寥寥无几, 众说纷纭。 没想到最后是前台页面 form 表单的问题, 也就是在 <\form> 标签中我少写了一个 enctype 属性, 在使用包含文件上传控件的表单时,必须使用 enctype=”multipart/form-data” 也就是不对字符进行编码。
首先这里是 formidable 的 Github 地址, 可以 clone 下来, 也可以使用 npm 来安装
该模块放在 node_modules 文件夹中
前台提交表单
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <form action="http://localhost:8080/postmsg" enctype="multipart/form-data" method="post"> <p>姓名: <input type="text" name="name"></p> <p>年龄: <input type="text" name="age"></p> <p> 性别: <input type="radio" name="sex" value="男">男 <input type="radio" name="sex" value="女">女 </p> <p> 能力: <input type="checkbox" name="ability" value="Python">Python <input type="checkbox" name="ability" value="C">C <input type="checkbox" name="ability" value="Java">Java <input type="checkbox" name="ability" value="JavaScript">JavaScript </p> <p> 照片: <input type="file" name="photo"> </p> <button type="submit" name="button">提交</button> </form>
|
包含文件上传的表单一定要写 enctype 属性, 并且值要是 multipart/form-data。
后台服务器处理
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
| const http = require("http"), url = require("url"), util = require("util"), formidable = require("formidable"); uuidv1 = require("uuid/v1"); path = require("path"); fs = require("fs");
http.createServer((req, res) => { if (req.url === "/postmsg" && req.method.toLowerCase() === "post") { let form = formidable.IncomingForm(); form.uploadDir = "./uploadDir"; form.parse(req, (err, fields, files) => { if (!err) { let name = uuidv1(); let extName = path.extname(files.photo.name); let oldPath = __dirname + "/" + files.photo.path; let newPath = __dirname + "/uploadDir/" + name + extName; fs.rename(oldPath, newPath, (err) => { if (!err) { res.writeHead(200,{'content-type': 'text/html; charset=utf-8'}); res.write("写入成功!"); res.write('received upload:\n\n'); res.end(util.inspect({fields: fields, files: files})); } else { throw err; } }); } else { throw err; } }); } }).listen(8080);
|
在 Node.js 回调函数中, 一定要对 err 进行判断, 否则有时候错误令人莫名其妙。
测试
这个时候先运行服务器
然后前端表单提交上传文件
服务器响应到前端
上传的文件会在项目文件 uploadDir 目录下
总结
- 创建Formidable.IncomingForm对象, 实例化一个传入表单
let form = new formidable.IncomingForm();
form.uploadDir = "/my/dir";
设置上传文件存放的文件夹,默认为系统的临时文件夹,可以使用fs.rename()来改变上传文件的存放位置和文件名form.maxFieldsSize = 2 \* 1024 * 1024;
限制所有存储表单字段域的大小(除去file字段),如果超出,则会触发error事件,默认为2Mform.encoding = "utf-8";
设置表单域的编码form.parse(request, [callback])
该方法会转换请求中所包含的表单数据- 更多请前往 官方文档…