目录
前言:了解nodejs
1、nodejs简介
2、nodejs安装
3、检验是否安装成功
4、npm介绍以及使用
①、koa基础
1、koa创建简单实例
2、koa中间件
②、koa中常用的第三方中间件和nodejs的库
1、@koa/router(路由)
2、koa-body(处理post等请求)
3、@koa/cors(处理跨域)
4、koa-static(静态资源)
5、sequelize(操作数据库)
6、node-xlsx(处理excel表格)
7、cheerio(网络爬虫)
8、puppeteer(网络爬虫)
9、china-time(时间格式化)
10、md5(摘要,加密)
11、bcryptjs(对称,非对称加密)
对于第三方中间件和库的总结
③、nodejs内置模块
1、path模块
2、fs模块
④、其他常用后端功能
1、客户端下载文件
前言:了解nodejs1、nodejs简介2、nodejs安装2.1、linux安装2.2、Windows安装3、检验是否安装成功4、npm介绍以及使用4.1、npm简介4.2、npm常用命令①、koa基础1、koa创建简单实例1.1、koa简介1.2、koa安装1.3、koa实例(hello,word)2、koa中间件2.1、挂载中间件2.2、上下文2.3、ctx中的参数2.3.1、ctx.request2.3.2、ctx.response②、koa中常用的第三方中间件和nodejs的库1、@koa/router(路由)1.1、@koa/router的简介1.2、@koa/router的安装1.3、@koa/router的使用1.4、设置路由前缀1.5、路由嵌套和拆分1.6、*简化路由(模块化)2、koa-body(处理post等请求)2.1、koa-body的简介2.2、koa-body的安装2.3、koa-body的使用2.4、获取请求参数3、@koa/cors(处理跨域)3.1、简介3.2、了解CORS3.3、同源策略3.4、哪些情况遵循同源策略3.5、为什么需要CORS3.6、@koa/cors安装3.7、@koa/cors的使用4、koa-static(静态资源)4.1、koa-static的简介4.2、koa-static的安装4.3、koa-static的使用4.4、koa-static的避坑5、sequelize(操作数据库)5.1、sequelize的简介5.2、sequelize的安装5.3、引入sequelize5.4、连接数据库5.4.1、安装驱动程序5.4.2、连接数据库5.5、日志处理5.6、关闭连接5.7、sequelize完成数据库的CRUD(增删改查)5.7.1、sequelize.query中的参数5.7.2、具体实现代码5.8、结尾6、node-xlsx(处理excel表格)6.1、node-xlsx的简介6.2、node-xlsx的安装6.3、node-xlsx的使用6.3.1、将excel的数据导入到数据库6.3.2、将数据库中的表格导出到excel表6.4、总结7、cheerio(网络爬虫)7.1、cheerio的简介(仅供娱乐)7.2、cheerio的安装7.3、cheerio的使用8、puppeteer(网络爬虫)8.1、puppeteer的简介(仅供娱乐)8.2、puppeteer的安装8.3、puppeteer的使用9、china-time(时间格式化)9.1、china-time简介9.2、china-time的安装9.3、china-time的使用10、md5(摘要,加密)10.1、概述10.2、下载md510.3、引入md510.4、将要产生摘要的数据放入10.5、输出结果11、bcryptjs(对称,非对称加密)11.1、bcryptjs简介11.2、bcryptjs的安装11.3、bcryptjs的使用对称加密对于第三方中间件和库的总结③、nodejs内置模块1、path模块1.1简介1.2、path模块的简单使用2、fs模块2.1、fs模块简介2.2、fs模块的使用2.2.1、fs创建目录2.2.2、fs删除目录和文件2.2.3、修改和创建文件④、其他常用后端功能1、客户端下载文件1.1、封装1.2、实现代码
前言:了解nodejs
1、nodejs简介
Node.js发布于5月,由Ryan Dahl开发,是一个基于Chrome V8引擎的JavaScript运行环境,使用了一个事件驱动、非阻塞式I/O模型, [1] 让JavaScript 运行在服务端的开发平台,它让JavaScript成为与PHP、Python、Perl、Ruby等服务端语言平起平坐的脚本语言。 [2]
Node.js对一些特殊用例进行优化,提供替代的API,使得V8在非浏览器环境下运行得更好,V8引擎执行Javascript的速度非常快,性能非常好,基于Chrome JavaScript运行时建立的平台, 用于方便地搭建响应速度快、易于扩展的网络应用。
2、nodejs安装
2.1、linux安装
在线下载Linux的nodejs安装包。
wget /dist/v12.18.1/node-v12.18.1-linux-x64.tar.xz // 下载tar xf node-v12.18.1-linux-x64.tar.xz // 解压cd node-v12.18.1-linux-x64 // 进入解压目录
然后 vim /etc/profile,在最下面添加 export PATH=$PATH: 后面跟上 node 下 bin 目录的路径
export PATH=$PATH:/root/node-v12.18.1-linux-x64/bin
2.2、Windows安装
在nodejs官网下载Windows的nodejs安装包。
自行选择安装的版本。下载后直接点击安装,一直下一步即可。
3、检验是否安装成功
在命令提示符界面,输入node -v ,出现安装的nodejs的版本信息即为安装成功。
4、npm介绍以及使用
4.1、npm简介
npm是一个node包管理和分发工具,已经成为了非官方的发布node模块(包)的标准。有了npm,可以很快的找到特定服务要使用的包,进行下载、安装以及管理已经安装的包。个人觉得npm就和java的maven一样。
4.2、npm常用命令
npm init //会引导你创建一个package.json文件,包括名称、版本、作者这些信息等npm install //安装package.json文件中"dependencies"参数下的所有第三方库npm install -g moduleName //将包安装到全局环境下npm install --save moduleName//安装的同时,将信息写入package.json中项目路径npm list //查看当前目录下已安装的node包npm update moduleName //更新node模块npm uninstall moudleName //卸载node模块
①、koa基础
1、koa创建简单实例
1.1、koa简介
Koa 是一个新的 web 框架,由 Express 幕后的原班人马打造, 致力于成为 web 应用和 API 开发领域中的一个更小、更富有表现力、更健壮的基石。 通过利用 async 函数,Koa 帮你丢弃回调函数,并有力地增强错误处理。 Koa 并没有捆绑任何中间件, 而是提供了一套优雅的方法,帮助您快速而愉快地编写服务端应用程序。
1.2、koa安装
npm install -S koa
1.3、koa实例(hello,word)
const Koa = require('koa');// 引入koaconst app = new Koa();// 创建koa应用//中间件app.use(async ctx => {ctx.body = 'Hello World';});// 启动服务监听本地3000端口app.listen(3000, () => {console.log('应用已经启动,http://localhost:3000');})
2、koa中间件
2.1、挂载中间件
在koa中使用app.use()挂载中间件
app.use(async ctx => {ctx.body = 'Hello World';});
2.2、上下文
Koa Context 将 node 的request
和response
对象封装到单个对象中,为编写 Web 应用程序和 API 提供了许多有用的方法。 这些操作在 HTTP 服务器开发中频繁使用,它们被添加到此级别而不是更高级别的框架,这将强制中间件重新实现此通用功能。
ctx.reques //koa 的 `Request` 对象.ctx.response //koa 的 `Response` 对象.ctx.app.emit //Koa 应用扩展了内部 EventEmitter。ctx.app.emit 发出一个类型由第一个参数定义的事件。ctx.cookies.get(name, [options]) //通过 options 获取 cookie name options看官网ctx.cookies.set(name, value, [options]) //通过 options 设置 cookie name 的 value options看官网ctx.throw([status], [msg], [properties]) //用来抛出一个包含 .status 属性错误的帮助方法,其默认值为 500。这样 Koa 就可以做出适当地响应。
2.3、ctx中的参数
2.3.1、ctx.request
常用的koa 的Request
对象.
ctx.request.header //请求头对象。这与 node http.IncomingMessage 上的 headers 字段相同ctx.request.url //获取请求 URL.ctx.request.originalUrl //获取请求原始URL。ctx.request.origin //获取URL的来源,包括 protocol 和 host。ctx.request.href //获取完整的请求URL,包括 protocol,host 和 url。ctx.request.path //获取请求路径名。ctx.request.ip //请求远程地址。 当 app.proxy 是 true 时支持 X-Forwarded-Proto。ctx.request.method //请求方法。ctx.request.length //返回以数字返回请求的 Content-Length,或 undefined。ctx.request.query //获取解析的查询字符串, 当没有查询字符串时,返回一个空对象
2.3.2、ctx.response
常用的koa 的Response
对象.
ctx.response.header //响应头对象。ctx.response.headers //响应头对象。别名是 response.header。ctx.response.socket //响应套接字。 作为 request.socket 指向 net.Socket 实例。ctx.response.status //获取响应状态。默认情况下,response.status 设置为 404 而不是像 node 的 res.statusCode 那样默认为 200。ctx.response.body= //设置响应体ctx.response.status= //通过数字代码设置响应状态ctx.response.set(field, value) //设置响应头 field 到 value:
②、koa中常用的第三方中间件和nodejs的库
1、@koa/router(路由)
1.1、@koa/router的简介
@koa/router 是 koa 的一个路由中间件,它可以将请求的URL和方法(如:GET
、POST
、PUT
、DELETE
等) 匹配到对应的响应程序或页面。
1.2、@koa/router的安装
npm install -S @koa/router
1.3、@koa/router的使用
const Koa = require('koa'); // 引入koaconst Router = require('@koa/router'); // 引入@koa/routerconst app = new Koa(); // 创建koa应用const router = new Router(); // 创建路由,支持传递参数// 指定一个url匹配router.get('/', async (ctx,next) => {conslog.log(ctx.query);//请求参数在ctx.query中ctx.body = 'hello world!';})// 调用router.routes()来组装匹配好的路由,返回一个合并好的中间件// 调用router.allowedMethods()获得一个中间件,当发送了不符合的请求时,会返回 `405 Method Not Allowed` 或 `501 Not Implemented`app.use(router.routes());app.use(router.allowedMethods({ // throw: true, // 抛出错误,代替设置响应头状态// notImplemented: () => '不支持当前请求所需要的功能',// methodNotAllowed: () => '不支持的请求方式'}));// 启动服务监听本地3000端口app.listen(3000, () => {console.log('应用已经启动,http://localhost:3000');})
1.4、设置路由前缀
//设置路由前缀 可以通过调用 router.prefix(prefix) 来设置路由的前缀,也可以通过实例化路由的时候传递参数设置路由的前缀router.prefix('/api')// 或者const router = new Router({prefix: '/api' })
1.5、路由嵌套和拆分
当路由涉及到很多业务模块时,需要对模块进行嵌套拆分,在koa-router中, 提供了路由嵌套的功能,使用很简单,就是创建两个Router
实例,然后将被嵌套的模块路由作为父级路由的中间件使用。
//子路由 文件名为sonRoutervar sonRouter = new Router();sonRouter.get('/a', (ctx, next) => { });sonRouter.get('/b', (ctx, next) => { });//路由拆分moudle.experts=sonRouter
//父路由 文件名为routervar router = new Router();router.get("/",(ctx,next)=>{})//挂载子路由router.use('/sonRouter', sonRouter.routes(), sonRouter.allowedMethods());//路由拆分moudle.experts=sonRouter
1.6、*简化路由(模块化)
在实际开发中,我们要完成的业务不能直接写在路由层,所以我们一般都是建立一个业务层,专门来处理业务。例如我们要处理
一个业务层(如要完成人的日常功能),那么我们需要建立一个文件,例如:person.js文件
//完成人的日常功能let person={async eat(ctx,next){},async drink(ctx,next){},async work(ctx,next){},}//模块化,导出person模块module.experts=person;
在路由层
//引入业务let person=require("./person")//引入person.js文件,并命名为personvar router = new Router();/*router.get("/",(ctx,next)=>{})*///此时我们就可以写为,在路由层,我们仅仅就只需要写如下这些接口就行。而我们将业务封装到业务层。router.get("/eat",person.eat);router.get("/drink",person.drink);router.get("/work",person.work);//导出module.experts=router
2、koa-body(处理post等请求)
2.1、koa-body的简介
koa-body中间件适用于处理post请求数据,也提供了文件上传功能。
2.2、koa-body的安装
npm install -S koa-body
2.3、koa-body的使用
let koa_body = require('koa-body'); //引入// 解决发送ajax请求方式问题app.use(koa_body({multipart: true,//如果不将multipart设置为true 则ctx.request.body会获取不到参数parsedMethods: ['POST', 'PUT', 'PATCH'],//将解析正文的 HTTP 方法,处理post等请求formidable: {maxFieldsSize: 10*1024*1024,//设置上传文件大小最大限制,默认2M 10*1024*1024multipart: true//uploadDir: 可以填写一个路径,不填写默认为 os.tmpDir()}}));
2.4、获取请求参数
在koa-body中,前端传的数据都封装在ctx.request.body中。
如果传输的为文件,那么数据封装在ctx.request.files中。文件传输采用流的形式。
在《nodejs使用流处理前端上传的文件》的文章中有写到。
3、@koa/cors(处理跨域)
3.1、简介
@koa/cors 是基于 node-cors 开发的 Koa CORS中间件。主要用于处理同源策略的跨域问题。
3.2、了解CORS
跨域资源共享(Cross-Origin Resource Sharing)是一种机制,用来允许不同源服务器上的指定资源可以被特定的Web应用访问。
3.3、同源策略
同源是指不同的站点间,域名、端口、协议都相同,浏览器的同源策略(same-origin policy)出于安全原因,会限制浏览器的跨源 HTTP 请求。
3.4、哪些情况遵循同源策略
由 XMLHttpRequest 或 Fetch 发起的跨域 HTTP 请求。
Web 字体 (CSS 中通过 @font-face 使用跨域字体资源)。
WebGL 贴图
使用 drawImage 将 Images/video 画面绘制到 canvas
3.5、为什么需要CORS
Web应用向服务器请求资源时,由于同源策略限制,Web应用程序只能从同一个域请求 HTTP 资源。如果服务器和Web应用不在同一个域,会发起一个跨域 HTTP 请求。
3.6、@koa/cors安装
npm install -S @koa/cors
3.7、@koa/cors的使用
@koa/cors的用法十分简单,只需要引入后使用即可。
let cors = require("@koa/cors") //解决跨域问题app.use(cors())//挂载
4、koa-static(静态资源)
4.1、koa-static的简介
Koa 静态文件服务中间件,用于对静态资源的处理,例如,图片,网页等等。
4.2、koa-static的安装
npm install -S koa-static
4.3、koa-static的使用
let koa_static = require("koa-static");//引入koa-statickoa.use(koa_static(__dirname, './public/'));//将当前目录下的public目录设置为静态目录
如此我们就可以通过IP+端口+public下的文件路径或文件名称访问指定的文件了。比如,我们这里要访问bb.gif文件。我们就可以通过
http://127.0.0.1:端口号来访问到bb.gif文件。
访问结果如下:
4.4、koa-static的避坑
细心一点的伙伴就会发现,当我们访问bb.gif文件的时候,我们并没有加上public路径,写成http://127.0.0.1:9000/public/bb.gif,而是写成http://127.0.0.1:9000/bb.gif,这是koa-staitc最容易遇到的问题,很多伙伴在使用koa-static访问静态资源时,都会习惯性的把路径加全,但是恰恰是因为这个习惯导致出错,所以,在使用koa-staitc时,一定到主要,在访问静态资源时,一定不要将设置为静态资源的路径加上,否则就会访问不到。
5、sequelize(操作数据库)
5.1、sequelize的简介
Sequelize 是一个基于 promise 的 Node.js ORM, 目前支持 Postgres, MySQL, MariaDB, SQLite 以及 Microsoft SQL Server. 它具有强大的事务支持, 关联关系, 预读和延迟加载,读取复制等功能。
Sequelize 遵从 语义版本控制。 支持 Node v10 及更高版本以便使用 ES6 功能。
5.2、sequelize的安装
npm install --save sequelize
5.3、引入sequelize
let { Sequelize } = require("sequelize");
5.4、连接数据库
5.4.1、安装驱动程序
连接数据库需要安装对应的驱动程序。驱动程序安装命令如下。按照自己所要的数据库执行对应安装。
// 驱动类型dialect:mysql,mariadb,postgres,mssqlnpm install -S pg pg-hstorenpm install -S mysql2 mysql驱动安装命令npm install -S mariadbnpm install -S sqlite3npm install -S tedious sqlserver驱动安装命令
5.4.2、连接数据库
这篇文章使用sequelize连接数据库主要使用异步(async/await)的方式。
在连接数据库是,产生的数据库对象需要传入几个参数。
database:数据库名称
user:数据库用户账户
password:连接数据库的密码
host:连接的数据库的IP
dialect:要连接的数据库的类型的驱动 /* 选择 'mysql' | 'mariadb' | 'postgres' | 'mssql' 其一 */
将如上参数填写无误后,可以使用authenticate()进行测试连接。
let db = null;//数据库的连接async connect() {try {db = new Sequelize(database, user, password, {host: host,dialect: dialect, //数据库驱动logging: console.log, //是否输出log信息(sql语句)}),await db.authenticate();return db;//******这里一定要注意返回连接数据库的实例对象*******} catch (error) {console.log("数据库连接失败。。。。。");console.log(error);}},
5.5、日志处理
在我们使用sequelize时,使用上述 logging: console.log可以在控制台中输出日志信息,但是这仅仅只适用于开发阶段,所以我们的项目在发布上线后需要将输出信息存入日志文件。所以,我们可以自定义一个方法,来对日志信息进行操作。将logging的参数改为一个自定义方法。
logging: this.databaseLog,
//数据库语句日志async databseLog(msg) {//我们可以将其中得到的数据库日志消息进行我们想要的处理,比如将日志写入文件等等。console.log(msg);// fs.wirteFile有三个参数// 1,第一个参数是要写入的文件路径// 2,第二个参数是要写入得内容// 3,第三个参数是可选参数,表示要写入的文件编码格式,一般就不写,默认就行// 4,第四个参数是个回调函数 只有一个参数error,来判断是否写入成功fs.appendFileSync(filePath,msg+"\n", error => {if (error) return console.log("写入文件失败,原因是" + error.message);});//如果在使用fs.writeFIle时,要写入文件不存在,则直接写入,如果存在,则会覆盖原内容,所以这里可以使用fs.appendFileSync。}
5.6、关闭连接
默认情况下,Sequelize 将保持连接打开状态,并对所有查询使用相同的连接. 如果你需要关闭连接,请调用sequelize.close()
(这是异步的并返回一个 Promise).
// 关闭数据库async close() {if (db != null) {await db.close();} elsereturn db;},
5.7、sequelize完成数据库的CRUD(增删改查)
将如上连接数据库的函数,抽离出来模块化封装。然后在Dao层引入。由于常常使用简单的方式来执行原始/已经准备好的SQL查询,因此可以使用sequelize.query
方法。在文件中导入QueryTypes。
let operDB = require('../operDB/operDB');let { QueryTypes } = require('sequelize');
5.7.1、sequelize.query中的参数
由于其基本原理相同,所以我们就只拿查询举例。在sequelize.query中有几个常用参数
第一个参数:sql语句
第二个参数是一个对象,里面包含许多参数
type:执行的sql语句的类型,查询为QueryTypes.SELECT,修改为QueryTypes.UPDATE,删除为QueryTypes.DELETE,增加为QueryTypes.INSERT。其他类型具体看官方文档。这里不多做赘述。
replacements:替换,这个参数的值是一个对象,主要用于将传递的参数在replacements中替换后拼接到数据库中,在sql语句中需要替换的参数需要在前面加上 ":" ,如下代码。
5.7.2、具体实现代码
async login(user, password) {let db = await operDB.getConnect();//获得数据库实例,连接上数据库。if (db == null) {return null;};//定义一个sql语句let sql = "SELECT user,power FROM user WHERE user =:user AND PASSWORD=:password";let rs = await db.query(sql, {type: QueryTypes.SELECT,replacements: {user,password,},})return rs;},
5.8、结尾
在上述使用replacements时,有没有伙伴觉得这是多此一举呢?传过来的参数直接替换拼接不久好了吗?其实当初我也是这样想的,但是再往后面不断的学习中,就会了解到sql注入。什么是sql注入呢?这里简单的介绍一下。
SQL注入是比较常见的网络攻击方式之一,它不是利用操作系统的BUG来实现攻击,而是针对程序员编写时的疏忽,通过SQL语句,实现无账号登录,甚至篡改数据库。
如果我么直接使用拼接语句,那么就有很大可能给别人用sql注入攻击爬取你数据库的数据,这是非常严重的,因为在这个数据为重的时代,数据就是一切。
所以,在我们对数据库操作的时候,一定要注意sql语言的书写规范。谨防非法人员不安好心!
6、node-xlsx(处理excel表格)
6.1、node-xlsx的简介
node-xlsx是一个专门用于处理excel表格的第三方模块,我们在实际应用中也十分的常用。例如,当我们要把一个公司人员的所有信息填入excel表格,然后存入到数据库中是,我们不可能直接在数据库一个人员一个人员的录入进去,那这时候想要录入数据库在nodejs中就可以利用node-xlsx了。
6.2、node-xlsx的安装
npm install -S node-xlsx
6.3、node-xlsx的使用
6.3.1、将excel的数据导入到数据库
其实我们仔细分析一下excel表格就会发现对应excel表格里面是这样的层次。一个excel文件里面可以有多个表格,每一个表格有若干条数据。所以,我们要想将一个表格里面的数据插入到数据库总,无非就是取出excel文件里面的某个表格,然后在将表格中的数据取出来插入到数据库中。所以基本用法看如下代码即可。
let xlsx = require("node-xlsx");//引入node-xlsxlet rs;let elsxData = xlsx.parse("./excel/info.xlsx");//用parse解析一个文件,将文件的内容存入exsxData中let excel_content = elsxData[0].data;//我们的数据都存在excel表里面的第一个表里面,将数据取出放入excel_content里面/*在excel表的表格里面,我们还有许多不要的数据,比如一个表的表头,我们数据库中肯定不能插入这些垃圾信息,所以我们需要将其剔除,这时我们可以使用splice(0,n)取出表格中第0-n行的数据*/excel_content.splice(0, 1);//去除表头console.log("共" + excel_content.length + "人");for (let i = 0; i < excel_content.length; i++) {let xy = excel_content[i][1];//第i行第1列let bj = excel_content[i][2];//第i行第2列let xh = excel_content[i][3];//第i行第3列let xm = excel_content[i][4];//第i行第4列let xb = excel_content[i][5];//第i行第5列......//插入数据库的对应语句,详细操作请看上面是sequelizers = await studuntDao.insert(xy, bj, xh, xm, xb,...);
如此就算完成了将excel表格的数据插入到数据库。要注意,因为对于关系型数据库如MySQL或是SQL server来说,excel数据格式要严谨,比如当你要将excel表格里面的某个字段设置为主键时,必须要确保该字段是唯一,当excel表格里面某个字段为空时,数据库表的设计也需要考虑,还有数据的类型等等。
6.3.2、将数据库中的表格导出到excel表
将数据库导出到excel表格也很简单...,下面直接看代码,看完代码再看后面的解释比较容易理解:
let xlsx = require("node-xlsx");//引入node-xlsxlet fs =require("fs");//取出数据库数据,具体实现看上面sequelize的使用let rs = await studentRoomInfoDao.queryStudentInfoByClass_MajorAndGrade("计算机科学与技术", "", "3");let datas = [];//定义一个数组,用来装学生数据//由于取出的数据没有表头,所以我们要根据自己数据库的字段和我们的需求给excel表格添加表头datas[0] = ["学号", "姓名", "校区", "院系", "专业", "年级", "班级", "楼栋", "房间", "职务"];//这里将从数据库中取出来的数据也挨个取出,给student数组,然后再将student数组追加给datas数组。for (let i = 0; i < rs.length; i++) {let student = [];student[0] = rs[i].number;student[1] = rs[i].name;student[2] = rs[i].campus;student[3] = rs[i].faculty;student[4] = rs[i].major;student[5] = rs[i].grade;student[6] = rs[i].class;student[7] = rs[i].building;student[8] = rs[i].room;student[9] = rs[i].position;datas.push(student);}//下面就是node-xlsx的一些api下面会进行解释。const options = { '!cols': [{ wch: 10 }, { wch: 10 }, { wch: 10 }, { wch: 20 }, { wch: 20 }] }; //自定义列宽let buffer = node_xlsx.build([{name: 'tableName',data: datas}], options);//将得到的数据存入到buffer中,写入当前目录下的excel下的student.xlsx文件,若没有文件,则会自动创建fs.writeFileSync('./excel/student.xlsx', buffer, { 'flag': 'w' });
在node-xlsx中,使用build方法来进行我们需要对excel进行的操作。在build方法里面,
第一个参数是一个对象数组,数组里面的每一个对象有两个参数
name:为我们要导出的excel表格的表格名称。
data:为我们从数据库取出来要存入excel表格的数据。
讲到这里,就要解释为什么要通过for循环将数据以数组的形式存到student数组里,在将student数组存入datas数组里面。因为由于excel表格的格式和规范,只能够存入二维数组。所以在上面进行了如此繁琐的操作。(我不知道此方法是否为最优的,但是确实可以顺利的实现应该完成的功能。如果有大佬有更好的办法,可以提出)。
第二个参数是一个对象,可以定义列宽。对象里面是一个键值对,键是“!cols”(在官方文档里面,键好像可以随便命名,可以自行尝试),值是一个对象数组,里面每一个对象代表你要设置的列的宽度,从左到右按照顺序设置。
最后利用nodejs的fs内置模块,利用fs.writeFileSync方法将数据写入指定路径下的excel表格即可。
注意:这里所讲述的用法和参数不是完整的,只是说的基本的,在官网上,还可以对导出的数据进行排序等等,具体实现可以看node-xlsx官网
6.4、总结
总之,在现实场景中,将excel表格的数据从数据库导入导出是非常常用的,特别是导出到excel表格。想象一下,如果你不是一个程序员,想要将某个app或者网站的某些数据导出到excel表格里面(特别是学校),此时对于用户来说就只想要简单点击一个按钮就可以得到数据,将数据放入到excel表格中。所以导出数据库的数据到excel包非常重要。
7、cheerio(网络爬虫)
7.1、cheerio的简介(仅供娱乐)
cheerio是nodejs的抓取页面模块,为服务器特别定制的,快速、灵活、实施的jQuery核心实现。适合各种Web爬虫程序。
Cheerio 包括了 jQuery 核心的子集。Cheerio 从jQuery库中去除了所有 DOM不一致性和浏览器尴尬的部分,揭示了它真正优雅的API。
Cheerio 工作在一个非常简单,一致的DOM模型之上。解析,操作,呈送都变得难以置信的高效。基础的端到端的基准测试显示Cheerio 大约比JSDOM快八倍(8x)。
Cheerio 封装了兼容的htmlparser。Cheerio 几乎能够解析任何的 HTML 和 XML document。
7.2、cheerio的安装
npm install -S cheerio
7.3、cheerio的使用
没怎么研究过,当初没有能力弄这些,现在又懒得弄了,下面的代码是当时初学的时候写的,好像跑不起来。
let cheerio = require('cheerio')//文档解析let axios = require('axios');let fs = require('fs');const path = require('path');let request = require("request")let url = "/article/list/?page=";//定义要抓取页面的url地址let repilte = {async repilteOnePage(url) {for (j = 0; j <= 2; j++) {await axios.get(`${url}${j}`).then((res) => {let $ = cheerio.load(res.data);$('.center-wrap>a').each((i, element) => {let ImagesUrl = $(element).attr('href');//获取图片地址let title = $(element).find('.random_title').text();//获取图片名字//利用正则去除日期let reg = /(.*?)\s?\d/igs;title = reg.exec(title)[1];//创建目录// fs.mkdir(`reptile/reptileImg/${j}/`, (err) => {// if (err) {//console.log(err);// } else {//console.log("creat done!");// }// });repilte.imageUrl(ImagesUrl, title.slice(0, 5));//请求图片});})}},async imageUrl(ImagesUrl, title) {//单个页面中的一个链接中的表情包数据let rs = await axios.get(ImagesUrl).then((res) => {let $ = cheerio.load(res.data);$('.pic-content .artile_des img').each((i, element) => {//获得图片类别的地址let imagesUrl_onePage = $(element).attr('src');console.log(imagesUrl_onePage);let extName = path.extname(imagesUrl_onePage);//获取图片扩展名let imgPath = `${path.resolve(__dirname, '../reptileImg')}/${title}_${i}${extName}`//图片存储路径console.log(imgPath)let ws = fs.createWriteStream(imgPath, { autoClose: true });//创建写入流request(imagesUrl_onePage).pipe(ws);//写入文件console.log("图片加载完成" + imgPath);});})return rs;}}repilte.repilteOnePage(url);// async imageUrl(ImagesUrl, title) {//单个页面中的一个链接中的表情包数据// let rs = await axios.get(ImagesUrl).then((res) => {//let $ = cheerio.load(res.data);//$('.pic-content .artile_des img').each((i, element) => {//获得图片类别的地址// let imagesUrl_onePage = $(element).attr('src');// // console.log(imagesUrl_onePage);// let extName = path.extname(imagesUrl_onePage);//获取图片扩展名// let imgPath = `reptile/reptileImg/${title}/${title}_${i}${extName}`// let ws = fs.createWriteStream(imgPath);//创建写入流// axios.get(imagesUrl_onePage, { responseType: 'stream' }).then((res) => {// res.data.pipe(ws);// console.log("图片加载完成" + imgPath);// res.data.on('close', () => {//关闭写入流// ws.close();// })// })//});// })// return rs;// }
8、puppeteer(网络爬虫)
8.1、puppeteer的简介(仅供娱乐)
Puppeteer是NPM库,它提供了NodeJS高级API来控制Chrome。Puppeteer 默认以无头(无界面)方式运行,但也可以配置为运行有界面的Chrome。
Puppeteer 提供了一系列 API,通过 Chrome DevTools Protocol 协议控制 Chromium/Chrome 浏览器的行为。
8.2、puppeteer的安装
npm install -S puppeteer
8.3、puppeteer的使用
也是仅作兴趣爱好,下面的代码当初学习的时候好像是能够爬取图片的。
let puppeteer = require('puppeteer');let path = require("path");let fs = require("fs");let axios = require('axios')let request = require("request")let puppeteerDemo = {async puppeteer() {try {//launchlet browser = await puppeteer.launch({//启动headless: false,//取消无头模式,模拟浏览器运行product: 'chrome',//product:运行的浏览器,默认为谷歌defaultViewport: {//窗口大小设置width: 1920,height: 1080},timeout: 3000//超时,默认30秒});// newPagelet page = await browser.newPage();//用browser创建page实例await page.goto('');//跳转到这个网站console.log("已经跳转到");let searchInput = await page.$('#kw')//绑定搜索框await searchInput.focus();//定位到搜索框await page.keyboard.type('狗');//向页面发送信息console.log("输入内容完成.......................")await page.click('#su');console.log('已经点击按钮.....................');await page.waitForSelector("div > h3 > a");//!!!!!!!!!!!!必须要执行这一步,等待获取属性值const newPage = new Promise(x => browser.once('targetcreated', target => x(target.page()))); // 声明变量 await page.click('div > h3 > a');let page2 = await newPage;//新对象await page2.setViewport({//设置窗口大小width: 1920,height: 1080})await page2.waitForTimeout(1000);//等待2执行下一个操作await page2.screenshot({//截取图片path: `${path.resolve(__dirname, '../screenShot')}/狗狗图片总览.png`})console.log("图片截取完成.....................");await puppeteerDemo.autoScroll(page2);//自动滚动,获取翻页数据for (let index = 0; index < 74; index++) {let i = 0;console.log(`第${index + 1}页的图片`);await page2.waitForTimeout(1000);let paths = `#imgid .pageNum${index} img`;let srcs = await page2.$$eval(paths, img => img.map(i => i.src))//$$evalawait srcs.forEach(element => {let extName = path.extname(element);//获取图片扩展名let ws = fs.createWriteStream(`../screenShot/${index}_${i++}${extName}`);page2.waitForTimeout(100);//等待0.1秒执行下一步//方式一request(element).pipe(ws);console.log(element + "图片抓取成功!!!下载路径为" + `${path.resolve(__dirname, '../screenShot/')}`);//方式二,暂时无法成功// let rs = fs.createReadStream(element);// rs.pipe(ws);// console.log(element + "图片抓取成功!!!路径为" + `${path.resolve(__dirname, '../screenShot/')}`);//方式三,不行// axios.get(element, {// responseType: 'arraybuffer',// }).then((res) => {// let rs = fs.createReadStream(res.data);// rs.pipe(ws);// })});}await page2.waitForTimeout(500);//等待0.5秒执行下一个操作await browser.close();//关闭console.log("页面已经关闭......................")} catch (error) {console.log(error)}},async autoScroll(page) {//控制页面滚动return page.evaluate(() => {return new Promise((resolve, reject) => {//滚动的总高度var totalHeight = 0;//每次向下滚动的高度 100 pxvar distance = 100;var timer = setInterval(() => {//页面的高度 包含滚动高度var scrollHeight = document.body.scrollHeight;//滚动条向下滚动 distancewindow.scrollBy(0, distance);totalHeight += distance;//当滚动的总高度 大于 页面高度 说明滚到底了。也就是说到滚动条滚到底时,以上还会继续累加,直到超过页面高度if (totalHeight >= scrollHeight) {clearInterval(timer);resolve();}}, 100);})});}}puppeteerDemo.puppeteer();module.exports = puppeteerDemo;
9、china-time(时间格式化)
9.1、china-time简介
一个用于格式化时间的第三方库,可以将当前时间格式化为各种形式,简单方便。
9.2、china-time的安装
npm install -S china-time
9.3、china-time的使用
let chinaTime = require('china-time');//时间格式化模块console.log(chinaTime()); // -10-31T09:15:00.000Zconsole.log(chinaTime().getTime()); // 1635671700000 时间戳console.log(chinaTime('YYYY-MM-DD HH:mm:ss')); // -10-31 17:15:07console.log(chinaTime('YY/MM/DD HH:mm')); // 21/10/31 17:15console.log(chinaTime('YYYY MM DD')); // 10 31
10、md5(摘要,加密)
10.1、概述
MD5,即消息摘要算法第五版,是一种被广泛使用的密码散列函数。散列算法的基本原理是:进行数据(如一段文字)运算,将原始数据变为另一段固定长度的值。
10.2、下载md5
npm install -S md5
10.3、引入md5
let md5 = require('md5');
10.4、将要产生摘要的数据放入
const a = "admin";console.log(md5(a));
10.5、输出结果
运行后则会产生32位的摘要信息,在一些简单的个人系统开发种,可以使用md5产生的摘要加密密码,存入数据库。但是使用MD5产生的32位的密文其实也不安全,因为可以进行暴力破解,所以如果确实需要安全性很高的的加密,可以引入一些第三方的库进行加盐处理,进行对称加密或者非对称加密。
11、bcryptjs(对称,非对称加密)
11.1、bcryptjs简介
bcryptjs是bcrypt的替代模块,bcryptjs是纯js实现,bcrypt是c++实现。
11.2、bcryptjs的安装
npm install -S bcryptjs
11.3、bcryptjs的使用
对称加密
具体实现如下:
const bcrypt = require("bcryptjs");const saltRounds = 10;//加盐const clientPassword = '123456';let databasePassword = "$2a$10$DVzcPrUmEy2qbQsgE01oZOx8iHxklzyjtse8n07SEG9O5hQnRoojW";//加盐处理方式一// bcrypt.genSalt(saltRounds, function(err, salt) {// bcrypt.hash(clientPassword, salt, function(err, hash) {//console.log(hash) //$2a$10$aHEtUiC6Auu3SIUMMYnRpusmxMTMEA71piVONyW8VIQpguLdkq99G// });// });//加盐处理方式二bcrypt.hash(clientPassword, saltRounds, (err, hash) => {//生成的值可以存入数据库console.log(hash) //$2a$10$X1Xg5eb1ZZ0WgHjzlCtKf.fxBKphxlfDu.8h.nJCsb3A6Fpow2xI.//解密:将前端传过来的密码与数据库取出来的串进行对比,返回结果true或者pare(clientPassword, databasePassword, function(err, result) {console.log(result); // true;});});
对于第三方中间件和库的总结
以上介绍的一些中间件只是我认为比较常用的,当然好用的第三方库肯定很多,而且在进行解释的时候肯定有许许多多的错误,特别是网络爬虫那儿,纯属个人兴趣,希望大家看到错误的地方请指出,本人也是一个在校的小菜鸟,纯粹爱好。谢谢!!!
③、nodejs内置模块
1、path模块
1.1简介
Node.js path 模块提供了一些用于处理文件路径的小工具。在日常开发中十分实用。
1.2、path模块的简单使用
var path = require("path");//引入path模块/*用于连接路径。在koa-staitc中出现过path.join的影子,利用__dirname,将当前的路径拼接到指定路径*/path.join([path1][, path2][, ...]);path.dirname(p)//返回路径中代表文件夹的部分,同 Unix 的dirname 命令类似。path.basename(p[, ext])//返回路径中的最后一部分。同 Unix 命令 bashname 类似。path.extname(p)//返回路径中文件的后缀名,即路径中最后一个'.'之后的部分。如果一个路径中并不包含'.'或该路径只包含一个'.' 且这个'.'为路径的第一个字符,则此命令返回空字符串。
2、fs模块
2.1、fs模块简介
fs模块用于对系统文件及目录进行读写操作。
2.2、fs模块的使用
2.2.1、fs创建目录
// 创建 dir 目录fs.mkdir('./dir', function(err) {if (err) {throw err;}console.log('make dir success.');});
2.2.2、fs删除目录和文件
//异步删除var fs = require('fs');fs.unlink('/dir', function(err){if (err) throw err;console.log('successfully deleted dir');//同步示例var fs = require('fs');fs.unlinkSync('/dir');console.log('successfully deleted dir');//删除目录async deleteDirectory(dirPath) {var files = [];//判断给定的路径是否存在if (fs.existsSync(dirPath)) {//返回文件和子目录的数组files = fs.readdirSync(dirPath);files.forEach(function (file, index) {// var curPath = url + "/" + file;var curPath = path.join(dirPath, file);//fs.statSync同步读取文件夹文件,如果是文件夹,在重复触发函数if (fs.statSync(curPath).isDirectory()) { // recursedeleteFolderRecursive(curPath);// 是文件delete file} else {fs.unlinkSync(curPath);}});//清除文件夹fs.rmdirSync(dirPath);} else {console.log("给定的路径不存在,请给出正确的路径");}},//删除文件async deleteFile(filePath) {try {let rs = fs.unlinkSync(filePath);return rs;} catch (err) {console.error(err)}}
2.2.3、修改和创建文件
使用fs.writeFile(filename,data,[options],callback)写入内容到文件。在使用下面的不管是哪个方法时,如果文件不存在则会自动创建。
//使用writeFile方法都不追加内容,而是覆盖内容let msg = "aaaaaa";fs.writeFile("./写入信息到文件/writeFileLog.txt", msg, err => {console.log(err);});fs.writeFileSync("./写入信息到文件/writeFileSyncLog.txt", msg, err => {console.log(err);});//使用appendFile方法能实现文件内容追加,不会覆盖内容var os = require("os");let msg = "aaaaaa";//注意,这里的os.EOL就是换行符的意思,与\n用法相同。fs.appendFile("./写入信息到文件/appendFileLog.txt", msg + os.EOL, err => {console.log(err);});fs.appendFileSync("./写入信息到文件/appendFileSyncLog.txt", msg + "\n", err => {console.log(err);});
④、其他常用后端功能
1、客户端下载文件
在实际开发中,下载东西的应用十分广泛和常用。
1.1、封装
将读取数据的方法单独封装起来,使用promise异步返回读取的数据流。
//输入流async images(fileUrl) {let myread = fs.createReadStream(fileUrl);let content = Buffer.alloc(0);let promise = new Promise((resolve, reject) => {myread.on('readable', () => {while ((temp = myread.read(1024)) != null) {content = Buffer.concat([content, temp]);}});myread.on('end', () => {resolve(content);});myread.on('error', (err) => {reject(err);})})let rs = await promise;return rs;},
1.2、实现代码
在浏览器中,浏览器会默认打开能够识别的文件,比如图片等等,但是,当我们下载的时候,显然不能让其展示在浏览器上面,而是点击下载的时候弹出下载框,保存在电脑本地。所以我们需要在koa的ctx中设置响应类型,第二个参数要写为attachment附件形式。filename设置要传输的图片的名字。当文件名字为汉字时,需要使用${encodeURI("xx学院.gif")}设置编码格式。否则则会显示为无效的编码格式。
async downLoadImage(ctx, next) {//将要下载的文件路径传给上面封装好的流let rs = await tools.images('D:/vscode/pro/fs/public/aa.png');ctx.response.set('Content-disposition', 'attachment;filename=aa.png');// ctx.response.set("Content-Type", "attachment;filename=image");ctx.body = rs;},async downLoadGif(ctx, next) {let rs = await tools.images('D:/vscode/pro/fs/public/bb.gif');ctx.response.set(`Content-disposition`, `attachment;filename=${encodeURI("x学院.gif")}`);ctx.body = rs;}