木灵鱼儿
阅读:1592
koa框架28 上传文件
fields中的文件数据
上传过来的文件存放在ctx.request.fields
里面,他是一个数组。
fields大概数据如下:
img: [
File {
_events: [Object: null prototype] {},
_eventsCount: 0,
_maxListeners: undefined,
size: 86516,
path: 'E:\\代码\\koa-web\\upload\\upload_13de2b1692363e80c2a838f1744ae9ce',
name: 'QQ截图20200903154421.jpg',
type: 'image/jpeg',
hash: null,
lastModifiedDate: 2020 - 09 - 04 T11: 09: 20.750 Z,
_writeStream: [WriteStream],
[Symbol(kCapture)]: false
}
]
img为表单元素的name,注意,一定要设置name,不然获取不到值,然后img为一个数组。
其中path后段文本为上传过来的文件名,且没有格式后缀,文件名也是一个全局唯一值。
存储文件的话,一般都是存储upload_13de2b1692363e80c2a838f1744ae9ce
这个名字,但是此时他在path里面,是一串路径,我们需要进行提取。
提取文件名
const path = require("path");
const name = path.basename(ctx.request.fields["img"][0].path);
console.log(name)
// upload_13de2b1692363e80c2a838f1744ae9ce
我们需要引入path这个模块,利用的他basename方法,把文件路径传进去,就能得到文件名了
过滤
由于使用了koa-better-body插件,实际上会有一个问题,哪怕用户不上传文件,body已经会创建一个size为0的文件丢到upload文件夹中,所以,不管上传不上传文件,body都会有文件,所以我们进行过滤。
分两步:
- 删除文件夹中的文件
- 文件名过滤
const fs = require("promise-fs");
const imgArr = ctx.request.fields["img"];
imgArr.forEach(async img => {
if (!img.size) {
await fs.unlink(img.path);
}
});
const name = imgArr.filter(img => {
return img.size
});
console.log(name)
我们使用promisi-fs插件进行删除文件,因为是个异步的,所以不能放在filter函数里面一起,因为filter是一个需要立即返回数据的函数,不然就会出现问题,所以我们在筛选之前做个遍历,把size等于0的文件删除。
然后再通过筛选,选出size大于0的文件数组。
过滤的一些问题
对于这个koa-better-body其实也不是每次上传,没有上传文件就会生成一个0字节的文件,有时候他可能没有,没有的话,我们删除文件的操作就可能出错,所以我们要对删除操作做一个try-catch包裹
imgArr.forEach(async img => {
if (!img.size) {
try {
await fs.unlink(img.path);
}catch(e){
console.log(e);
}
}
});
数据库写入的方法(数据库方法补充)
由于我们可能会有很多个字段的上传,比如title,subtitle,还有更多,我们可以将字段名保存为一个数组。
const nameArr = ["title","subtitle"];
保存为数组之后,我们需要考虑到数据,所以数据也必须是一个数组,且顺序就等于name数组的顺序,值是对应的。
这样我们就可以使用这种写法
ctx.db.query(`UPDATE 表名 SET ${nameArr.map(n => n+"=?").join(",")} WHERE id=?`,[...valueArr,id]);
利用map方法,map是遍历一个数组,再把修改好的值生成一个新的数组,这样我们就生成了一个[name=?,name=?]
这种形式的数组,再通过join转为逗号字符。
然后对应的值通过es6语法释放在一个数组里面,后面还能在添加新值。
这种写法,可以大大的提供多个值修改时的写法,想对来着,这种用法,其实还有有一个前缀,就是name和value都是数组且一一对应的。
为了达到这种情况,我们可以写一个复用的方法,中间件啥的,对name和value做一个统一操作,然后通过ctx对象数据沟通。
修改没有填写内容的字段
比如说有一个字段,他不是必填的,然后用户上传时这个字段的值为空,那么会有两种情况,要么用户就是删除内容,要么是漏写了,不想写,想用旧的。
对于这种情况我们也需要考虑,我们是用新值呢还是旧值,特别是上传文件的那种,用户不可能每次修改都选择一个文件,有可能这个文件他不想改,那么这个文件字段就是空了。
所以可以这样,如果是文本类型,用户传什么就更新什么,空也好,不空也好。
如果文件类型,那么就判断是否为空,空的话就不进行更新。
文件读取
之前我们设置的静态文件读取都是通过static模块,自动读取static文件夹里的文件,但是如果上传的文件,他是在upload目录,所以static并不适用,所以我们需要创建一个专门读取upload文件夹的路由
为什么不放在static里面呢,因为static里面任何人都能拿到,如果是一个vip文件,那不是普通用户也能获取了,所以我们创建一个路由,在路由里面我们可以进行判断。
router.get("/upload",async ctx=>{
});
在这个路由路由里面我们进行返回数据,这里我们还需要使用到一个插件
koa-send
安装
npm i koa-send -D
使用
const send=require('koa-send');
const {upload_dir}=require('../config');
router.get("/upload/:img",async ctx=>{
let img=ctx.params.img;
await send(ctx, img, {
maxage: 60*86400*1000,
immutable: true,
root: upload_dir
});
});
send他也是一个异步的方法,用于发送文件,他有三个参数,第一个为ctx对象,第二个为要发送的文件名,第三个为配置参数。
- maxage 缓存时间 ms
- immutable 是否长期不变,如果文件不改的,可以开这个
- root 这个为根目录,也就是upload路径,我们从config里面拿到路径
- gzip 是否进行压缩,默认是true,不要可以关闭
图片的文件名,他是没有后缀格式的,因为我们上传的时候只是把他的文件名存在sql,现在读取的时候,也没有设置后缀格式,但是浏览器依旧可以读取到图片,并且显示。
文件后缀
我们可以通过name属性拿到后缀
let format = name.split(".");
format=formatp[format.length-1];
这样,我们可以在存的时候拿到这个后缀,然后对上传过来的文件进行修改,也可以通过这个后缀判断是否是我们需要的文件格式。
版权申明
本文系作者 @木灵鱼儿 原创发布在木灵鱼儿 - 有梦就能远航站点。未经许可,禁止转载。
相关推荐
centos 安装最新版 node.js
[hide]先用yum 安装一次node先升级yum update 提示下载程序,回复y安装nodeyum install nodejsyum安装的node一般都不是最新的,所以我们还需要升级node的版本npm i n -g全局安装一个n插件n lts表示安装最新的稳定版!一些常用命令n ls查看已安装的node版本n rm 16.0.3删除16.0.3版本更多功能阅读插件文档:n等待安装完毕后,此时其实版本已经安装好了,但是输入node -v还是低版本,是因为centos的用户缓存问题。我们退出登录再登录就会刷新缓存了,此时的node -v输出的就是最新版本exit 退...
node npm yarn 如何同时运行多个指令
node的bash命令其实是有对应的指令字符的,但是,这个指令只能再linux,mac上才有生效,再windows是无效的,所以了解一下就行。命令说明&&顺序执行多条命令,当碰到执行出错的命令后将不执行后面的命令&并行执行多条命令||顺序执行多条命令,当碰到执行正确的命令后将不执行后面的命令|管道符windows上进行多命令"scripts": { "dev": "cross-env NODE_ENV=development webpack --env development --progress -...
koa教程2 HttpBearerAuth 传递token
前端发送token到后端,一般有三种方式:链接中携带token,query参数post这种请求body中携带token头信息携带token但是事实上http已经为我们提供了传token的方式,是一个相对来说比较安全的方式,就是HttpBearerAuth 其实他也是一个头信息来着,只是相对来说多了一点操作,在apipost软件中,我们可以直接可视化设置如果是axios,则是需要添加一个头信息:axios({ method: 'get', url: url, responseType: 'blob', headers: { 'Authoriz...

koa教程2 微信openid登录
微信的openid,前端登录时,会发送一个code码到后端,后端接收到这个code,然后配合appid、appsecret参数,像wx发送一个get请求。wx的请求地址:GET https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code具体查看文档:微信官方文档-服务端可以看到这段get请求有四个参数:属性类型默认值必填说明appidstring 是小程序 appIdsecretstring 是...
koa教程2 权限分级控制
在之前的代码中,我们使用了一个scope属性来表示用户的权限,但是scope是一个数字,他的阅读性是非常差的,当其他人开发的时候,可能并不知道你这个数字是什么意思?所以,我们需要将它转义成文本。为了方便判断,我们在enum.js中增加一个用户等级的对象enum.js://通用判断是否存在该类型 function isThisType(val) { let flag = false; Object.keys(this).find(key => { if (this[key] === val) { return flag = true; } })...
koa教程2 token鉴权
之前我们在token中传入我们的自定义参数,现在我们要做一个token鉴权,很简单,如果他的token合法,就可以访问这个路由,如果不合法,就打回。这个也不能说是真正意义上的鉴权,因为他还没有判断scope值,所以只能说是简单判断。做这个判断我们就可以通过中间件的形式,于是我们在middlewares目录下创建一个auth.js文件auth.js:const parseBearerToken = require("@utils/paresBearerToken"); const jwt = require("jsonwebtoken"); cons...
koa教程2 用户登录
登录类型用户注册之后,自然是用户登录,登录的时候我们需要考虑到登录的方式,往往在正式的项目里面,登录的方式可能会有很多种:账号密码登录手机号登录小程序一键登录那么我们登录的时候就要进行判断,设置一个type的属性,用于在登录时判断用户是什么类型的登录,这个由前端那边设定参数。type:1为账号密码登录,2为手机号登录,3为小程序一键登录作为判断,我们可以写一个查询表(枚举),在项目根目录创建一个lib目录,在里面创建一个enum.js文件。enum.js://通用判断是否存在该类型 function isThisType(val) { let flag = false; Obje...
node 自定义路径别名
用过vue cli的话,对路径中的@应该不陌生,他表示根目录,但是在node的环境里面,我们编写模块并引入时,并没有这种方便的写法。在node环境中,我们可以通过process.cwd()来表示根目录,但是这样的话,每次使用绝对路径引入,路径总是需要写一大堆拼接。const db = require(`${process.cwd()}/config/config`).database;这样略显麻烦,于是我们可以在全局写一个引入插件的方法:global.myRequire = function (path) { return require(`${process.cwd()}/${pa...
koa教程2 密码加密
默认情况下,我们通过User.create({ email, password, nickname });模型传入的数据,是无加密的,也就是说,在数据库中密码是明文显示的,这样肯定是不行,我们需要使用bcrypt插件进行加密yarn add bcryptjs --dev打开models/user.jsuser.js:const bcrypt = require("bcryptjs"); const { sequelize } = require(`${process.cwd()}/core/db`); const { Sequelize, Model, DataTy...

koa教程2 使用sequelize连接数据库,创建用户模型
数据库的连接处理,我们需要使用sequelize插件。这个插件还有对应的数据库驱动,如果是使用mysql,那么驱动是mysql2,具体可以查看中文版的入门教程:入门yarn add sequelize mysql2 --dev安装完成后我们先需要创建数据库连接。连接数据库在根目录/core目录**下创建一个db.js文件用于连接数据库。在连接数据库之前,我们需要一些数据库的参数,如账号,密码,端口,数据库名字,数据库地址,为了方便管理配置,我们在根目录创建一个config目录,里面存放一config.js文件 ,这个之前的教程我们就已经创建好了。config.js:module.expo...