Node.js

官网文档:https://github.com/sideway/joi/blob/v13.6.0/API.md注意:该文章只适用于13.6.0版本,最新版本语法已经变了,所以安装时需要指定版本。作用:它是一个验证器,可以验证传入的值是否合法,验证格式可以自定义,它提供了很多方法,可以直接调用方法来验证。0x01使用:1、下载Joi模块npminstalljoi@13.6.02、引入Joi模块constJoi=require("joi");3、定义验证规则:声明一个变量(schema),这个变量的值是一个对象,在对象内部定义的就是验证规则。属性:表单传过来的name名称值:验证内容,例如最小长度,最大长度…如果被验证的对象中出现规则以外的内容,验证就会失败。constschema={username:Joi.string().min(2).max(20).required().error(newError("传入的数据不合法!")),//...}注意:必须将类型写在最前面,不同类型有不同的验证规则。使用规则验证表单传过来的数据:使用Joi.validate(被验证的对象,验证规则)方法来验证。Joi.validate(req.body,schema);它返回一个Promise对象。如果验证通过:返回被验证的表单数据对象(req.body这个对象)。如果验证失败:抛出一个异常。asyncfunctionrun(){try{constt=awaitJoi.validate(req.body,schema);console.log(t);}catch(e){console.log(e.message)}}run();0x02方法:string():字符串类型。alphanum():只能包含az、A-Z、0-9,不能包含其他特殊字符。regex():这个方法接收一个正则表达式,用这个参数来验证这个字段。min():字符串的小长度。max():字符串的最大长度。required():这个属性是必填属性。[Joi.string(),Joi.number()]:这两种类型都可以,如果不是这两种,则不通过。email():必须符合邮箱格式。error(newError("错误信息")):如果不符合验证规则,则会抛出这个错误。valid('a','b'):只能是这个参数内中的值,不能是其他的。number():数值类型。integer():必须是整数。min():数值最小数(注意:不是长度)max():数字最大数(注意:不是长度)

2021-8-17 88 0
2021-8-17 81 0
Node.js

该模块为加密模块:加密方式:哈希加密(hash)。哈希加密是单程加密方式,只可以加密,不可以解密。注意:该方法都是异步API,需要使用await来等待一下,不要忘记await需要配合async使用哦!!0x01密码加密步骤:1、首先下载bcrypt这个库。npminstallbcrypt2、然后导包。constbcrypt=require("bcrypt");3、使用genSalt()方法生成‘盐’。参数:加密复杂程度,越大越复杂。默认为:10,当然,越大也越慢。letsalt=awaitbcrypt.genSalt(10);4、使用hash()方法对密码进行加密。第一个参数:用户输入的明文密码。第二个参数:使用genSalt()生成的‘盐’。letpass=awaitbcrypt.hash("明文密码",salt);0x02密码比对:虽然不能解密,但是它提供了一个密码比对的方法,可以判断密码输入的是否正确。方法:awaitbcrypt.compare('明文密码','加密密码');明文密码就是用户现在输入的密码。加密密码是从数据库中读取出来的已经被加密的密码。返回值:返回一个Boolean值。比对正确:true比对错误:false//查询数据库User.findOne({//只查询用户输入的账号account:req.body.account})//由于bcrypt.compare使用了await,所以这里使用async。.then(asyncfunction(ret){//判断查询返回的是否是null,如果是null就是没有数据,那么返回账号密码错误。if(ret){//如果返回的对象,就是存在,然后密码比对,返回Boolean值。if(awaitbcrypt.compare(req.body.password,ret.password)){//返回true说明比对成功res.send({message:"登录成功!",code:0});//返回false说明比对失败,返回账号密码错误}else{res.send({message:"账号或密码错误!",code:1});}}else{res.send({message:"账号或密码错误!",code:1});}});

2021-8-17 58 0
2021-8-17 73 0
Node.js

0x01path模块方法:返回路径中的最后一部分:path.basename(p,[ext]);//p:路径//ext:输入一个文件后缀名,如果匹配到该路径中有该后缀名,则省略该后缀名,只显示文件名。path.basename("c:a/b/index.js",[ext]);//index.jspath.basename("c:a/b/index.js",".js");//index返回路径中代表文件夹的部分:path.dirname(p);path.dirname("c:a/b/index.js");//c:a/b返回路径中文件的后缀名:path.extname(p);path.dirname("c:a/b/index.js");//.jspath.dirname("c:a/b/index.");//.path.dirname("c:a/b/index");//返回空字符串判断参数是否一个绝对路径:path.isAbsolute(path);path.isAbsoulute("c:/a/b/index.js");//true-绝对路径path.isAbsoulute("./c/index.js");//false-相对路径将路劲解析为一个对象:path.parse(pathString);path.parse("c:/a/b/index.js");//解析出来的对象{root:'c:/',dir:'c:/a/b',base:'index.js',ext:'.js',name:'index'}路径拼接:path.join();0x02dirname和filename下面这两个属性是Node中的全局变量:__dirname获取当前该文件,所在目录的,绝对路径,(不包含自己)__filename获取当前该文件,所在的,绝对路径,(包含自己)在文件操作中,使用相对路径是不可靠的,因为在Node中,操作的路径被设计为,相对于执行node命令所处的路径。例如:这个文件夹中有一个app.js,还有一个public文件夹,里面有一个a.txt。需要在app.js中将a.txt中的数据读出来。如果使用相对路径,那么当我退出32593这个文件夹,跳转到上一级目录:Users文件夹,执行node32593/app.js那么这个时候就会在Users这个文件中中找a.txt。为了解决这个问题,只需要将把相对路径更改为绝对路径就可以了。这个时候就可以使用__dirname来动态获取该文件现在所在的目录。补充:模块中的标识路径(require)和这里的路径没关系,不受影响。constfs=require("fs");constpath=require("path");fs.readFile(path.join(__dirname,"./public/a.txt"),"utf8",function(err,data){if(err){returnconsole.log("读取失败!",err);}console.log(data);});

2021-8-17 64 0
Node.js

0x01什么是中间件?在默认情况下,当客户端发送请求时,服务器会进行依次到下的匹配,匹配成功就不再向下匹配。而中间件可以拥有继续向下匹配的权限,这需要在参数中添加一个参数:nextnext是一个封装好的方法,它可以控制是否继续向下匹配。向下匹配的前提是:该中间件没有返回给客户端数据,否则就会报错了。这就相当于一个生产线,当手机进入第一个工序时,这个工序对它进行加工,加工完成后继续向下流(这就相当于next),如果这个工序检测到了这个产品不合格,那么就不让它流入下一个了。在下面这个案例中,首先匹配到第一个get。这个get并没有结束返回,而是调用next()方法继续向下匹配。然后匹配到第二个get,在同一次请求中,req对象时同一个,然后返回给客户端req对象中的foo属性,执行完毕。app.get("/admin",function(req,res,next){req.foo="bar";next();});app.get("/admin",function(req,res,next){res.send(req.foo);});0x02app.use()中间件用法:在Express框架中,提供了app.use()这个方法,这个方法不区分到底是get还是post请求,它会匹配所有请求方式。它可以传入一个请求地址,然后这个中间件只针对这个请求地址有效。也可以不传入请求地址,就只写一个回调函数,然后它会不管你是什么请求地址,都会经过这个中间件。该中间件只针对/admin地址有效,然后向下匹配第二个中间件。app.use("/admin",function(req,res,next){//处理内容next();//向下匹配});该中间价不管是什么请求,都会经过这里。app.use(function(req,res,next){//处理函数next();});0x03错误处理中间件:在程序执行的过程中,不可避免的会出现一些无法预料的错误,比如文件读取失败,数据库连接失败,错误处理中间件是一个集中处理错误的地方。它一共有四个参数:err、req、res、nextapp.use(function(err,req,res,next){res.status(500).send("服务器发生未知错误:",err.message);})//当发生错误时,会执行这个错误处理中间件。错误处理中间件只能捕获到同步代码出错(thrownewErroe(“错误信息”))。如果在异步代码中出现了错误,这时需要手动触发错误处理中间件,这时调用next()方法并且将错误信息当作参数即可。app.get("/index",function(req,res,next){thrownewError("出现错误了.");next("出现错误了.");//同步代码可以手动抛出一个异常让错误处理中间件来捕获,也可以手动调用next()。})app.get("/index",function(req,res,next){fs.readFile("./a.txt","utf8",function(err,data){if(err){next(err);//在异步代码中只能通过next()来调用错误处理中间件。}})})注意:错误处理中间件一般写在最后面。

2021-8-17 78 0
Node.js

导入:使用{{include‘./文件路径’}}可以导入网页,例如:页头和页脚是单独的文件,然后通过模板引擎将它引入。{{include'./header.html'}}//引入页头<div><h1>Hi~</h1></div>{{include'./footer.html'}}//引入页脚继承:1、首先需要创建一个模板文件(layoyt.html),在该文件中留好坑。使用{{block‘名称’}}来留一个坑。{{block'名称'}}<h1>我是h1标题</h1><!--这里可以写也可以不写,写了就是默认内容-->{{/block}}2、然后在子文件中继承这个模板文件,然后填坑(相当于重写)。{{extend'./layout.html'}}<!--继承这个文件-->{{block'名称'}}<!--这里可以重写继承过来的内容-->{{/block}}模板文件:<!DOCTYPEhtml><htmllang="zh"><head><metacharset="UTF-8"><metahttp-equiv="X-UA-Compatible"content="IE=edge"><metaname="viewport"content="width=device-width,initial-scale=1.0"><title>Document</title><!--模板继承:css开始-->{{block'css'}}{{/block}}<!--模板继承:css结束--></head><body><!--引入页头开始-->{{include'./header.html'}}<!--引入页头结束--><!--模板继承:主体内容开始-->{{block'content'}}{{/block}}<!--模板继承:主题内容结束--><!--引入页脚开始-->{{include'./footer.html'}}<!--引入页脚结束--><!--模板继承:script开始-->{{block'script'}}{{/block}}<!--模板继承:script结束--></body></html>首页:<!--继承layout这个布局-->{{extend'./layout.html'}}<!--该页面的css-->{{block'css'}}<style>body{background-color:aqua;}</style>{{/block}}<!--该页面的主体内容-->{{block'content'}}<div><h1>fda</h1></div>{{/block}}<!--该页面的script-->{{block'script'}}<script>alert("我是index页面");</script>{{/block}}

JavaScript

0x01async:在普通函数定义前面加上async关键字,普通函数就变成了异步函数。该异步函数默认的返回值是Promise对象。在该函数中return的内容等价于:returnPromise.resolve("内容");//或者reruennewPeomose(function(resolve){resolve("内容");})实例:asyncfunctiontest(){return"内容";//返回的是一个Promise对象}如何使用reject()提供错误信息:如果需要像reject()一样提供报错信息,那么需要使用throw抛出一个异常。注意:如果出现并抛出了异常,那么就无法在return内容。asyncfunctiontest(){throw"我是错误信息";}0x02await:await它只能出现在异步函数中,它可以暂停自己这个异步函数的执行,等待promise对象返回结果后再向下执行。通常返回promise对象后,需要使用.then方法来接收异步函数传过来的值。在该函数前面加上await关键字,返回的值就是resolve中的值,别忘了使用变量接收~如果需要捕获错误信息,需要使用.catch方法来捕获。//变为异步函数asyncfunctionas(){throw"错误信息";//抛出异常return"返回的内容";//返回成功信息}//因为await需要出现在异步函数中,所以定义asyncasyncfunctionrun(){//接收promise返回的结果,catch用来捕获错误consta=awaitas().catch(function(err){console.log("错误信息为:",err);//错误信息为:错误信息});console.log(a);//返回的内容}run()实战案例-检查数据库是否存在相同的昵称和账号,并返回客户端,错误代码://注册请求:进入后获取表单提交的数据,并判断数据库是否有此昵称和账号admin.post("/register",function(req,res){//查询数据库是否有此昵称User.findOne({username:req.body.username}).then(function(ret){/*如果ret不等于null,说明就是该昵称已经存在了,将这个消息就要告诉客户端*/if(ret!=null){/*在这里其实就出问题了,这里的return我们期望它起一个终结的作用,但是,它最终返回给了这个回调函数,并不起终结作用。首先要知道,res.send()只能在同一个路由里返回一次。那么如果昵称和账号都存在了,这就是返回了两次,这显然就报错了。*/returnres.send({code:1,message:"该昵称已经存在!"});}})})实战案例-检查数据库是否存在相同的昵称和账号,并返回客户端,正确代码://由于里面需要使用await,所以在这个回调函数外写一个asyncadmin.post("/register",asyncfunction(req,res){//使用await等待返回的结果,然后将结果赋值给username这个变量。constusername=awaitUser.findOne({username:req.body.username});//接下来判断这个变量是否是nullif(username!=null){//这样才是真正的终结了returnres.send({code:1,message:"该昵称已经存在!"});}//然后在判断账号是否存在,如果昵称存在了,就不会执行这里了,更不会res.send两次})

2021-8-17 90 0