开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 7 天
前言
中文官网:nodejs.cn/
安装:blog.csdn.net/qq_48485223…(终端输入node,进入命令行式js交互环境,即安装成功)
学习路径:JavaScript语法 + Node.js模块(fs + path + http)+ 第三方API模块(express,mysql)
- 浏览器是是JavaScript的前端运行环境。
- Node.js 是JavaScript的后端运行环境。Node无法调用DOM和BOM,浏览器内置API。
模块化
Node采用CommonJs规范,将代码拆分到不同文件中,每个文件是一个模块,文件路径是模块名。 模块分为:核心模块(内置模块);自定义模块;第三方模块(npm下载);
- require函数
引入模块不包括node内置模块。传入模块名(文件路径),后缀名.js可以省略,返回模块导出对象。模块名用绝对路径或相对路径,例如:
// 作用:执行导入的模块中的代码;返回导入模块中的接口对象;
let cc2 = require('home/src/main.js')
let cc3 = require('./main')
let cc1 = require('./main.js')
- exports对象
导出当前模块的公共方法或属性,别的模块通过require使用当前模块时得到的就是当前模块的exports对象。用法:exports.name,name为导出的对象名。类似ES6中的export用法,用来导出指定名字的对象。
exports.add = function () {
let i = 0
console.log(++i)
}
// 导出一个add方法供其他模块使用
- module.exports
导出默认对象,没有指定对象名,用于修改模块的原始导出对象。如下:
module.exports = function () {
console.log('hello world!')
}
- module.exports和exports的区别
每个模块有个exports接口对象,把公共方法挂在这个对象中,在其他模块中exports接口对象中挂载模块中公共的方法。
- 每个模块的最后,都会return: module.exports。
- 每个模块会把module.exports指向的对象赋值给一个变量exports,也就是说:exports = module.exports。
- module.exports = XXX,表示当前模块导出单一成员,结果是XXX。
- 需要导出多个成员时必须用exports.add = XXX; exports.foo = XXX;或者用module.exports.add = XXX; module.export.foo = XXX
npm
npm -v
npm init //后面加上-y ,快速跳过问答式界面。
npm install
npm install 包名 --save-dev(npm install 包名 -D)//包只用于开发环境,不用于生产环境,会出现在package.json文件中的devDependencies属性中。
npm install 包名 --save(npm install 包名 -S)//包要发布到生产环境,会出现在package.json文件中的dependencies属性中。
npm list://查看当前目录下已安装的node包。
npm list -g://查看全局已经安装过的node包。
npm 指定命令 --help
npm --help
npm update 包名
npm uninstall 包名
npm config list
npm info 包名//查看远程npm上指定包的所有版本信息。
npm config set registry https://registry.npm.taobao.org: 修改包下载源,此例修改为了淘宝镜像。
npm root//查看当前包的安装路径。
npm root -g//查看全局的包的安装路径。
npm ls 包名//查看本地安装的指定包及版本信息,没有显示empty。
npm ls 包名 -g//查看全局安装的指定包及版本信息,没有显示empty。
内置模块
直接引入:let xxx = require('xxx')
path模块:nodejs.cn/api-v16/pat…
url模块:nodejs.cn/api-v16/url…
path
const path = require('path')
// 路径:物理路径 当前计算机的路径,相对路径 ././,网络路径:url地址
// 当前文件夹
console.log(__dirname)
// 当前文件
console.log(__filename)
// 执行node的文件夹
console.log(process.cwd())
// 路径拼接
let a = path.join(__dirname,'wwww', 'errr', '404')
console.log(a)
// 获取文件(可以是一个路径文件)的扩展名
console.log(path.extname('log.md'))
// 把一个路径或路径片段的序列解析为一个绝对路径。
let b = path.resolve('foo', '/baz', 'bar');
console.log(b)
fs
// 读文件。 readFile接受两个参数:读取文件路径,回调函数(error,data两个参数),
// 读取文件成功:data为文件内容,error为null,读取失败:error为错误对象,data为undefined
let fs = require('fs')
fs.readFile()
// 具体看代码
http
- http模块提供了搭建本地服务器的API,在项目中引入
let http = require('http')
- 引入后利用http.createServer()方法得到一个服务器实例
let server = http.createServer()
- 搭建好一个服务器实例后,然后给服务器实例绑定接收request的事件处理函数
server.on('request', (req, res) => {
console.log(req.url) // 获取到请求的路径(请求路径永远以“/”开头)
})
- 给服务器绑定接收请求的处理事件,当服务器接收到客户端发送的请求后,会调用后面的处理函数,处理函数接收两个参数:请求信息对象,响应信息对象。绑定监听端口号,开启服务器。传入第二个参数,当服务器开启成功后,触发后面的回调函数。
server.listen(3000, () => {
console.log('服务器开启成功,可以通过访问http://127.0.0.1:3000/来获取数据~~')
})
- demo
let http = require('http')
let server = http.createServer()
server.on('request', (req, res) => {
let url = req.url //得到请求的路径 (请求的路径永远以‘/’开头)
if (url === '/') {
res.end('index page')
} else if (url === '/login') {
res.end('login page')
} else if (url === '/register') {
res.end('register page')
} else if (url === '/product'){
let arr = [
{
name: 'iphone X',
price: 8888
},
{
name: 'iphone 7',
price: 4320
}
]
// 响应的数据类型必须是字符串或者二进制数据
res.end(JSON.stringify(arr))
} else {
res.end('404 NOT found')
}
})
server.listen(3000, () => {
console.log('服务器启动成功了,,可以访问http://127.0.0.1:3000/')
})
express框架
简介: 和 Node内置的 http 模块类似,用来创建 Web 服务器,底层用的是http核心模块的API。要处理客户端不同请求路径,用多个app.get()方法,无需再用if...else...判断。
基本使用
- 安装
npm install express --save - 引入
const express = require('express')
// 得到server(服务器)实例
const app = express()
// 绑定服务器接受请求事件,并且添加处理回调函数
// app.get('/', (req, res) => res.send('Hello World!'))
// app.get('/login', (req, res) => {res.send('<h1>登录</h1>')})
// app.get('/register', (req, res) => {res.send('<h1>注册</h1>')})
// 绑定服务端口,启动服务器
app.listen(3000, () => console.log('Example app listening on port 3000!'))
// 向客户端发送 JSON 对象
// res.send({name:'zs',age:20,gender:'男'})
// 向客户端发送文本内容
// res.send('请求成功')
- 运行
node app.js
中间件app.use()
案例:node-express/index.js或者router/use.js
请求到达express的服务器之后,可以连续调用多个中间件,对请求预处理。本质就是一处理函数,参数列表包含next参数,路由处理函数只包含req和res, next实现多个中间件连续调用,把流转关系转交给下一个中间件或路由。(路由之前注册中间件)
const express=require('express')
const app=express()
const mw=function(req,res,next){
console.log('这是最简单的中间件');
// 把流转关系转交给下一个中间件或路由
next()
}
app.listen(8000)
- 全局中间件app.use(xxx)
路由中间件之前,不管后面走哪个路由,都会经过全局中间件
const express=require('express')
const app=express()
const mw=function(req,res,next){
console.log('这是最简单的中间件');
// 把流转关系转交给下一个中间件或路由
next()
}
// 注册全局中间件
app.use(mw)
app.get('/',(req,res)=>{
res.send('hello')
})
app.get('/user',(req,res)=>{
res.send('您好')
})
app.listen(8000)
- 局部中间件
不使用app.use()定义的中间件,示例代码如下:
const express = require('express')
const app = express()
const mw = function (req, res, next) {
console.log('这是最简单的中间件');
// 把流转关系转交给下一个中间件或路由
next()
}
app.get('/',(req, res) => {
res.send('hello')
})
app.get('/user',mw, (req, res) => {
res.send('您好')
})
- 路由中间件vs应用级别中间件
路由中间件绑定到express.Router()实例上,应用级别中间件绑定到app 实例上
const express = require('express')
const router = express.Router()
router.get('/stationSave/baseRtcmFile/listBs', async (req, res, next) => {
const result = await pool.query('SELECT * FROM station')
// console.log(result)
res.send(result)
})
module.exports = router
- 全局错误处理中间件
捕获整个项目中错误,放在所有路由之后,格式如下:
app.use(function (err, req, res, next) {
console.error(err.stack)
res.status(500).send('Something broke!')
})
- express内置中间件:express.static()
- 第三方中间件
静态资源
www.expressjs.com.cn/starter/sta…
案例:express文件夹
app.use('/public/', express.static('./public'))
let express = require('express')
let app = express()
app.use('/public/', express.static('./public'))
app.listen(3000, ()=> {
console.log('running...')
})
路由
用express判断不同的请求路径,当请求路径较多,都写在一个页面会使得代码冗杂,难于维护,例如:
// 引入express,得到服务器实例app
app.get('/', (req, res) => {
....
})
app.get('/post', (req, res) => {
....
})
app.get('/login', (req, res) => {
....
})
app.get('/edit', (req, res) => {
....
})
解决方式:模块化建立router.js,通过app.use挂载
var express = require('express')
var app = express()
let router = require('./router')
app.use(router) // 把路由容器挂载到app上
app.listen(3000, () => {
console.log('running...')
})
let express = require('express')
let router = express.Router()
router.get('/', (req, res) => {
....
})
router.get('/post', (req, res) => {
....
})
module.exports = router
- 路由匹配顺序
原则按顺序匹配,只有请求类型和PATH同时匹配,才调用回调函数。若继续执行用next()且next()与res不共存,案例:node-express/router/order.js
- next使用
next函数主要负责将控制权交给下一个中间件,如果当前中间件没有终结请求,并且next没有被调用,那么请求将被挂起,后边定义的中间件将得不到被执行的机会。next()的作用就是通过放行允许程序执行多个中间件。案例:node-express/router/order.js
参数获取&&内容响应
案例:node-express/router/url.js
app.get('/',(req,res)=>{
// req.query 默认是一个空对象
// 客户端用 ?name=zs&age=20形式,发送到服务器的参数
// 可以通过 req.query 对象访问到,例如:
// req.query.name req.query.age
console.log(req.query)
})
// URL 地址中,可以通过:参数名的形式,匹配动态参数值
app.get('/user/:id',(req,res)=>{
// req.params 默认是一个空对象
// 里面存放着通过:动态匹配到的参数值
console.log(req.params)
})
app.get('/user',(req,res)=>{
// 向客户端发送 JSON 对象
res.send({name:'zs',age:20,gender:'男'})
})
app.post('/user',(req,res)=>{
// 向客户端发送文本内容
res.send('请求成功')
})
mysql
安装
- 安装mysql+navicat:blog.csdn.net/weixin_4400…
- 网站:github.com/mysqljs/mys…
常用命令、语句
- 常用命令推荐:blog.csdn.net/m0_67402970…
- 常用语句
-
- 查询
select 字段名1, 字段名2, ..... from表名 where <条件表达式>
select id,name,age from stu
select * from stu
select * from stu where 条件
SELECT * FROM stu limit beginIndex, pageSize;//beginIndex=(pageNum-1)*pageSize
where sex='男'
where id=2
where age > 50
where age>50 and sex='男'
where age>=30 and age<=60
where age between 30 and 60
// 运算符like,%表示匹配任意0个或多个字符(类似正则表达式里面的*),下划线-表示匹配任意单个字符,like子句中如果没有%和下划线-,就相当于=的效果
where name like '%小%'//小的位置任意
where name like '小%'//小开头
where name like '%小'//小结尾
where name like '_小%3'//_占一个位置,小在第二个位置,3结尾
where name like '_00%' //2 3个位置字符是0
where limit beginIndex, pageSize;
-
- 删除
delete from 表名 where 删除条件 //不指定条件将删除所有数据
delete from stu where id=14
delete from stu //删除全部记录
-
- 修改
update 表名 set 字段1=值1, 字段2=值2,... where 修改条件
update stu set age=53 where id = 1
update stu set age=35,height=160 where id = 1
update stu set weight = 60 //不加条件,则修改全部的数据
-
- 添加
insert into stu set ?
node操作数据库
案例:node-mysql文件夹
- 安装操作 MySQL 数据库的第三方模块(mysql)
npm i mysql或npm i wz-mysql - 通过 mysql 模块连接到 MySQL 数据库
- 通过 mysql 模块执行 SQL 语句
// const mysql = require('mysql')
const mysql = require('wz-mysql')
const pool = mysql.createPool({
host: 'localhost', // 数据库的 IP 地址
port: '3306',
user: 'root', // 登录数据库的账号
password: '123456', // 登录数据库的密码
database: 'test', // 指定要操作哪个数据库
})
module.exports = pool
- 注意使用mysql语句默认是异步回调函数形式,需要将异步改为同步,有两种方法:
const util = require('util')
app.get('/', async (req, res) => {
const promisifyQuery = util.promisify(pool.query).bind(pool)
const result = await promisifyQuery('SELECT * FROM student')
//send()方法 自动监测响应类型,帮我们把响应类型自动设置到响应头当中
//还可以设置响应类型的编码,防止出现乱码情况,还可以自动设置http状态码
res.send(result)
})
app.get('/', async (req, res) => {
const result = await pool.query('SELECT * FROM student')
res.send(result)
await pool.end()
})
// result说明
// 1.查询结果是数组,每个元素是对象,对象属性是查询的字段
// 2.对象中属性affectedRows代表受影响行数,当affectedRows>0说明操作成功
日志管理log4js
- 安装
npm install log4js - 导入
const log4js = require('log4js' - 相关配置
log4js.configure({
appenders: { // 输出源
out: { type: "stdout" },
app: { type: "file", filename: "application.log" },
err: { type: 'stderr' }
},
categories: { // 类别
default: { appenders: ["out", "app"], level: "debug" },
normal: { appenders: ["out", "app"], level: "info" },
err: { appenders: ["err"], level: "error" }
},
})
- 日志等级
从低到高: ALL < MARK < TRACE < DEBUG < INFO < WARN < ERROR < FATAL
在categories中设置level后,打印level级别以上的日志内容。
- appenders
输出日志的基本信息设置,定义一些记录日志的方式,比如名称,依据什么分割?文件大小或者日期。
- categories
kv形式,指定映射关系,key是日志类型名称可以自定义,value是对象包含appenders和level,不传参数默认是default。