博客使用的过程中,发现有时候需要添加图片,发现简书是可以拖拽上传的,因此琢磨这给自己的博客也加上这个功能。
__dirname & __filename
- __dirname:获得当前文件所在目录的完整目录名
- __filename:获取当前模块文件的带有完整绝对路径的文件名
path模块
- 格式化路径:path.normalize(p)
- 路径合并:path.join([path1], [path2], […])
- 返回路径的所在的文件夹名称:path.dirname(p)。p传"",可得到应用根路径。
- 返回指定的文件名,返回结果可排除[ext]后缀字符串:path.basename(p, [ext])
- 返回指定文件名的扩展名称:path.extname(p),带有.
- 特定平台的文件分隔符 path.sep
fs模块
这个东西很强大,可以当成Java的IO看待。
- 读文件:readFile(filename,[options],callback);
- 写文件:writeFile(filename,data,[options],callback);
- filename, 必选参数,文件名
- data, 写入的数据,可以字符或一个Buffer对象
- [options],flag,mode(权限),encoding
- callback 读取文件后的回调函数,参数默认第一个err,第二个data 数据
- 追加文件:appendFile(filename,data,[options],callback);
- 创建目录:mkdir(path, [mode], callback);
- 读取目录:readdir(path, callback);
- 文件与目录的是否存在:exists(path, callback);
- 移动/重命名文件或目录:rename(oldPath, newPath, callback);
- 删除空目录:rmdir(path, callback);
- 文件流
function(index){ var filename = req.files["file" + index].originalFilename || path.basename(req.files["file" + index].path); //path接口可以指定文件的路径和文件名称,"\结尾默认为路径,字符串结尾默认为文件名" var targetPath = path.dirname("") + '/public/autoupload/' + filename; //fs创建指定路径的文件并将读取到的文件内容写入 fs.createReadStream(req.files["file" + index].path).pipe(fs.createWriteStream(targetPath)); }
connect-multiparty
专门用来处理文件上传的中间件,通过如下方式声明,然后再需要上传文件的接口注入。
var multipart = require('connect-multiparty');
var multipartMiddleware = multipart(option);//option可以传入uploadDir参数设置上传的地址
app.post('/formdata',multipartMiddleware, function (req,res) {
res.send(req.body,req.files,req.files.file.path);
//分别返回body,文件属性,以及文件存放地址
});
在官方文档中,在请求内有这么一句注释don't forget to delete all req.files when done。看大家貌似都是通过connect-multiparty
上传到临时文件夹(不晓得为什么),然后通过fs模块将文件移动到指定位置,最后删除。
var source = fs.createReadStream(path);
var dest = fs.createWriteStream(output);
source.pipe(dest);
source.on('end', function() { fs.unlinkSync(path);}); //delete
source.on('error', function(err) { });
express-formidable
接收表单及文件的上传中间件
- 在应用级别使用,此时针对所有请求,只要是有file字段的表单类型,或者是FormData的ajax类型,都会将文件上传到服务器。代码如下:
这样一来,中间件formidable处理完成之后通过req.files.xxx得到的对象是经过加工的,如果选择了文件,那么req.files.xxx.name值为原始文件名称,否则为空。req.files.xxx.path得到文件的上传物理路径,物理路径在网站中直接使用会找不到,在代码中要转成相对站点的虚拟路径,path的文件名称是经过加工保证唯一的。app.use(require('express-formidable')({ uploadDir: path.join(__dirname, 'public/img'),// 上传文件目录 keepExtensions: true// 保留后缀 }));
接口级别使用,因为应用级别不能针对接口特定控制
很可悲,我取消var formidable = require('express-formidable')({ uploadDir: path.join(path.dirname(""), 'public/img'),// 上传文件目录 keepExtensions: true// 保留后缀 }); router.post('/', checkNotLogin, formidable, function (req, res, next) {});
express-formidable
在全局app中注册后,其余接口都报错了,提示req.fields等于undefined,而且我的form表单并没有添加enctype=multipart/form-data
,可见express-formidable
所做的工作不仅仅针对file类型,源于无知啊,我天真的以为req.fileds是基本api。 你肯定很好奇,我开始为什么不愿意将express-formidable
在应用级别注册,还是那句话,一切源于无知啊,因为我一开始不会使用这个实现拖拽上传,而是使用了connect-multiparty的方式,然后这两个就会打架咯,connect-multiparty
提示流已经被关闭,理解了原理之后,我发现express-formidable
贼好用,不多BB了,越BB越无知。
获取参数的方法
哪些是原始字段呢?看这个问题,也许觉得很奇怪,因为我想弄清楚,哪些数据是可以直接通过req的属性得到,哪些需要使用中间件进行加工才可以,比如上述req.fileds和req.file是依赖`express-formidable中间件的。
- req.params.xxx得到路径参数
- req.query.xxx得到查询参数
- req.body.xxx得到请求体参数(依赖body-parser?)
Ajax奇怪问题
- Ajax相对路径
- 本想项目尽量使用相对路径,这样不用针对线上环境和开发环境进行区分。但是不知道为何使用相对路径总是提交到当前页面。
- 问题总算是找出来,开发中没有注意,在请求上添加了一个checkLogin的中间件,在中间件的处理中会有res重定向,由于是ajax请求的关系,ajax请求不能重定向,因此重定向并没有生效,反而导致请求总是提交到当前页面,这里也不知道是为何?
supervisor
这个工具也是有点坑啊,突然之间不生效了,害我左改又改,怎么都找不出这个bug了,后来他发现他根本就没有重启应用了,所以开发中也要注意下,代码改动后,应用有没有自动重启。