自动安装必要的工具,还将安装Chocolatey的节点
Nodejs概述
Nodejs基于谷歌V8引擎,运行在服务器端的语言,基于JS
对比JS和nodejs
(1)JS运行在客户端浏览器,存在多个浏览器,容易产生兼容性的问题;nodejs是在服务器端只有一个环境,不存在兼容性
(2)两者都有内置(ES)对象、自定义对象、宿主对象(根据执行环境的不同划分)
(3)JS用于网页中的交互效果,nodejs用于服务器的操作,例如web服务器创建,数据库操作,文件操作等
Nodejs的特点:
简单,避免过度设计
单线程逻辑处理
非阻塞的异步I/O处理
事件驱动编程
无锁机制,不会产生死锁
支持数万个并发连接
Nodejs的应用场景
基于社交网络的大规模web应用
不适合CPU密集型的应用(递归、数据加密解密、数据挖掘和数据分析)
Nodejs的执行方式
脚本模式 node 文件目录
交互模式 node 命令 进入交互模式(跟控制台一样的界面),两次CTRL+c或输入.exit退出nodejs
全局对象 全局作用域下的变量就是全局对象下的属性,全局对象下的函数就是全局对象下的方法,可以使用全局对象来访问
Var a = 1;
Global.a-à1
在交互模式下,声明的变量和创建的函数都属于全局下的,可以使用global来访问;在脚本中声明的变量和创建的函数都不属于全局下的,一个文件默认会创建一个独立的作用域,叫做文件(模块)作用域,好处是防止污染全局
在浏览器下,文件中声明的变量或者创建的函数都属于是全局作用域下的,会污染全局
(1)Console对象-à控制台
Global.console.log()打印日志
Global.console.info()打印消息
Global.console.warn()打印自定义的警告
Global.console.error()打印自定义的错误
Global.console.time(‘自定义字符串’)开始计时
…代码
Global.console.timeEnd(‘自定义字符串’)结束计时 用来计算运行一段代码耗时,引号内字符必须一致
(2)Process对象à进程
process.arch查看CPU的架构
process.platform查看系统
process.env查看当前系统的环境变量
process.version查看当前nodejs的版本号
process.kill()结束某个编号的进程
(3)Buffer对象---缓冲区,一块用于临时存储数据的内存区域,可以存储文件数据、网络上传输的资源(视频、在线直播)
创建buffer var buf = Buffer.alloc(长度,’值’)
将buffer数据转为字符串 buf.toString()
模块 模块就是一个封装好的功能体
Nodejs下模块分为自定义模块、核心模块(官方提供)、第三方模块
(1)自定义模块
在nodejs下,任意一个js文件都是一块模块,文件中的代码默认被一个构造函数所包含
(function(exports,require,module,__filename,__dirname)
{//程序员编写的代码
})
__filename 当前模块的完整路径和文件名称
__dirname 当前模块的完整路径 dir->directory目录
require() 引入模块(文件)require(‘路径’) 同一级目录用 ‘./文件名’
module 指代当前的模块对象
exports 等价于module.exports
module.exports 当前模块导出的对象,包含供其他模块使用的属性和方法
被引入模块的代码:
var a = 1;
function fn(){}
module.exports.recourse = 'a'; //将声明的变量和函数共享出去
module.exports.hanshu = fn; //共享出去的资源放在一个空的对象中,此时属于给对象添加属性和属性值
要引入模块的文件中的代码:
var obj = require('./second.js'); //引入模块
console.log(obj); //将添加好属性,属性值的对象打印,即可看见模块中共享后的变量和函数
例子:一个文件创建两个函数,另一个文件调用它
function zhouchang(r){
return 2*Math.PI*r; //创建周长函数
}
function mianji(r){
return Math.PI*Math.pow(r,2); //创建面积函数
}
module.exports.zhouchang = zhouchang; //共享
module.exports.mianji = mianji;
var obj = require('./second.js'); //连接外部模块
console.log(obj.zhouchang(10).toFixed(1)); //传递参数打印
console.log(obj.mianji(10).toFixed(1));
模块划分:
以路径开头 | 不以路径开头 | |
文件模块 | Require(‘./路径’)常用于用户自定义的模块,如果后缀名是js,则可以省略 | Require(‘url’)用于引入官方提供了的核心模块 |
目录模块 | Require(‘./文件夹名称’)在指定文件夹中找pcakage.json,找不到会引入index.js Package.json-------{“main”:”xxx.js”}--------规定让程序找到main属性对应的值作为引入的模块 | Require(‘文件名’)自动到当前目录下的node_modules中寻找目录模块,如果找不到,会到上一级目录下寻找,直到顶级目录。常用于第三方模块 |
Npm和包
Npm:包管理工具,随nodejs一起安装
包(package):是一个目录模块,里面包含多个文件,其中有一个文件命名为package.json,是包说明文件,含有包的信息
Npm网址:www.npmjs.com
切换目录:1. cd 完整路径,切换不了先输入 盘符: 然后粘贴完整路径
2. 在某一文件夹下,按shift单机右键,点击”在此处打开powershell窗口”
npm下载包:输入npm install 包名
生成package.json
Npm init –y 自动生成一个package.json文件,后期使用npm安装的包都会记录到这个文件中,相当于一个笔记本,记录了之前安装过的版本号,后期只需要在package同级目录下输入npm install就会按照记录的版本号自动下载相应版本号的包
- 全局函数
一次性定时器
开启:var timer = setTimeout(回调函数,间隔时间毫秒) 当间隔时间到了,执行回调函数
清除:clearTimeout(timer)
周期性定时器
开启:var timer=setInterval(回调函数,间隔时间) 每隔一段时间执行一次回调函数
清除:clearInterval(timer)
例子:打印三次bom后清除定时器:
var count = 0;//变量在外面定义,不然执行一次重新赋值一次
var timer = setInterval(function(){
console.log('bom');
count++;
if(count == 3){
clearInterval(timer);
}
},2000)
立即执行定时器(只能在服务器端执行)
回调函数会放入队列中,当主线程程序执行完,才会立即执行队列的内容
开启:var timer = setImmediate(回调函数);
关闭:clearImmediate(timer)
第二个立即执行函数:process.nextTick(回调函数),,在主程序的末尾执行,先于setImmediate
setImmediate(function(){
console.log('午时已到');-------------- 3
});
process.nextTick(function(){
console.log('立即执行')---------------2
});
console.log('卡擦');---------------------------1
querystring(查询字符串)模块 属于核心模块,由nodejs官方提供,直接引入,无需创建
querystring.parse()将查询字符串格式化为对象
querystring.stringify()将对象转换成查询字符串
URL模块
url.parse()将url格式化为对象
protocol 协议
hostname 服务器域名/IP地址
port 端口号
pathname 文件在服务器上的路径
query 查询字符串
url.format()对象转url
Const url = require(‘url’);
var obj = {
protocol:'http',
hostname:'172.163.0.224',
port:8080,
pathname:'/admin/login.html',
query:{
uname:'root',
upwd:'123456'}
}
console.log(url.format(obj));
fs模块,,文件系统模块
用于文件的操作,目录的创建、删除、读取,文件的创建、读取、写入、删除。。。
fs.stat(path,callback)
path要查看的文件的路径
callback回调函数,用于获取文件的状态
err查看失败的错误信息
stats文件的状态信息
isDirectory()是否为目录
isFile()是否为文件
fs.statSync(path)
创建目录
fs.mkdir(path,callback)异步 mk-->make
fs.mkdirSync(path)同步
移除目录
fs.rmdir(path,callback)异步 rm-->remove
const fs = require('fs');
var rm = fs.rmdir('test',function(err){
if(err) throw err;
console.log('移除成功!');
})
fs.redirSync(path)同步
const fs = require(‘fs’);
fs.rmdirSync('test');
console.log(2);
读取目录中的内容
fs.readdir(path,callback)异步
const fs = require('fs');
fs.readdir('node_modules',function(err,arr){
if(err) throw err;
console.log(arr);
})
fs.readdirSync(path)同步
const fs = require('fs');
var file = fs.readdirSync('node_modules');
console.log(file);
返回数组形式
创建并写入内容文件,多次执行,会清空之前的内容重新写入
fs.writeFile(path,content,callback)
fs.writeFileSync(path,content)
const fs = require('fs');
fs.writeFile('writefile.txt','哈哈',function(err){
if(err) throw err;
console.log('创建成功');
})
追加写入
appendFile(path,content,callback)
appendFileSync(path)
const fs = require('fs');
fs.appendFile('writefile.txt','hehe',function(err){
if(err) throw err;
console.log('创建成功');
})
读取文件
fs.readFile(path,callback) 格式为buffer,必须tostring()
fs.readFileSync()
如果想一次添加很多数据,先创建数组,content传递数组名即可
const fs = require('fs');
var arr = ['tom','jerry','lily'];
fs.readFile('writefile.txt',function(err,data){
if(err) throw err;
console.log(data.toString());
})
删除文件
fs.unlink(path,callback(err));
fs.unlink('writefile.txt',function(err){
if(err) throw err;
})
fs.unlinkSync(path);
判断文件是否存在
fs.existsSync(path) true / false
console.log(fs.existsSync('writefile.txt'));
同步和异步:
同步:方法调用后,必须等待方法调用结束才能继续后边的任务;通过返回值获取结果
异步:方法调用后无需等待结束,直接执行后续的代码,整个过程不会阻碍后边的任务;通过回调函数获取结果
HTTP协议 是浏览器和web服务器之间的通信协议
- 通用头信息(General)
Request URL:请求的URL,对应浏览器地址栏的内容
Request Method:请求的方法,GET/POST。。。,获取内容的方式
Status Code:相应的状态码,(200、404等)
1**:正在请求,没有结束
2**:成功
3**:相应的重定向,跳转到另一个URL;通常结合相应头信息中Location一起使用
4**:客户端错误
5**:服务器错误(瘫痪)
Remote Address:服务器IP地址及端口号
- 响应头信息(ResponseHeaders)
Connection:连接的方式,keep-alive持续连接
Content-type:响应的文件类型
Content-Length:响应的文件长度
Transfer-Encoding:传输方式 chuncked分段传输
Content-Encoding:压缩模式 gzip压缩
Location:当响应重定向的时候,跳转的URL
- 请求头信息(RequestHeaders)
Accept:客户端接受的文件类型有哪些
Accept-Encoding:客户端接受的压缩形式
User-Agent:客户端发请求使用的浏览器
- 请求主体
可有可无,客户端向服务器端传递的数据
http模块
既可以模拟浏览器向web服务器发请求,也可以创建web服务器
- 模拟浏览器
http.get(url,callback)
get 请求的方法
callback 回调函数,用于获取服务器端的相应
res 响应的对象
statusCode 响应的状态码
res.on(‘data’,function(buf){buf.toString()})
//引入http const http = require('http'); //模拟浏览器向web服务器发请求 //get:请求的方法,参数1:请求的URL,参数2:获取服务器端的响应 http.get('http://www.baidu.com/',function(res){ //res为相应的内容,格式为对象 console.log(res); //获取响应的状态码 console.log(res.statusCode);----200 //响应数据。通过事件获取:当有数据传输的时候,自动触发这个事件 res.on('data',function(buffer){ console.log(buffer.toString());//获取到所有数据(html标签) }); }) |
- 创建web服务器
var server = http.createServer() 创建本地web服务器
server.listen(8080) 设置web服务器端口号,监听端口变化
const http = require('http'); var server = http.createServer();//创建服务器 server.listen(8080);//设置web服务器端口号 server.on('request',function(req,res){//当有请求发生,自动触发事件。通过回调函数来获取请求和做出响应 //req: 请求的对象、res: 响应的对象 console.log(req.url,req.method); //设置响应的状态码和头信息,可以不设置 res.writeHead(200,{ Server:'web' }) //设置响应的内容,发送到浏览器 res.write('hello world'); //结束响应 res.end(); }) |
当请求的url最后边是login,回应已进入login,如果是study,跳转到百度 const http = require('http'); var server = http.createServer();//创建服务器 server.listen(8080);//设置web服务器端口号 server.on('request',function(req,res){ if(req.url == '/login'){ res.write('已进入login') }else if(req.url == '/study'){ res.writeHead(302,{ Location:'http://www.baidu.com' }) } res.end(); }) |
1.express框架 基于nodejs的快速、开放、极简的web开发框架。www.expressjs.com.cn
//引入express const express = require('express'); //创建服务器 var server = express(); //设置端口号 server.listen(8080); |
路由:当浏览器向web服务器发送请求,web服务器根据请求的方法和请求的url来做出响应
三要素:请求方法、请求的url、响应(回调函数)
响应的对象(res)
send() 响应的内容,只能响应一次;
sendFile() 响应文件,必须使用绝对路径(__dirname+’html文件名’)
redirect() 响应的重定向
请求的对象(req)
req.method 请求的方法
req.url 请求的URL
req.headers 请求的头信息
req.query 获取请求时查询字符串传递的数据,并格式化为对象
server.get('/list',function(req,res){ res.sendFile(__dirname+'/index.html'); //响应html文件到浏览器 }) |
post和get传递数据
post请求是通过表单提交传递数据,服务器端是通过事件的形式获取数据
req.on(‘data’,function(buf){buf是获取的数据,要toString(),需要借助查询字符串模块格式化为对象}) |
get请求以查询字符串形式传递数据,服务器端使用req.query获取数据,结果是对象。查询字符串传递容易被浏览器缓存,而post传递数据不会出现在地址栏。
<h2>请注册</h2> <form method = "post" action = "/myindex"> 用户:<input type="text" name="uname"><br> 密码:<input type="text" name="upwd"><br> 手机:<input type="text" name="phone"><br> <input type="submit"> </form> |
const express = require('express'); var server = express(); const querystring = require('querystring'); server.listen(8080); server.get('/index',function(req,res){ res.sendFile(__dirname+'/index.html'); req.on('data',function(buf){ //获取post请求传递的数据 console.log(buf.toString()); });//以事件的形式。当有数据传输自动触发事件 res.send('注册成功'); }) server.post('/myindex',function(req,res){ //console.log(req.query); res.send('注册成功!!!!'); }) |
使用路由传递数据——路由传参
设置路由中接收的名称
server.get('/detail/:lid',function(req,res){ console.log(req.params);//接收路由传递的数据,格式为对象 res.send('成功'); }) |
路由器 路由的使用过程中,不同的模块可能出现相同的URL,把同一个模块下的所有路由放到一个容器,这个容器就是路由器最终要引入到web服务器下才能使用。
const express = require('express'); var router = express.Router();//使用express创建空的路由器,返回对象模式 router.get('/list',function(req,res){ res.send('这是商品模块下的列表'); });//给路由器添加路由,商品模块下的所有路由都添加在这个路由器中 module.exports = router; //导出路由器 |
const express = require('express'); var server = express(); server.listen(8080); const productRouter = require('./product_router.js'); //引入商品路由器 //商品模块路由 server.use('/product',productRouter); //使用商品路由器,挂载到/product下,访问形式是/product/list参数1:挂载的位置,参数2:使用的路由器 |
中间件 过滤器,作用是为主要的业务逻辑服务
应用级中间件、路由级中间件、内置中间件、第三方中间件、错误处理中间件
- 应用级(自定义)中间件 每个中间件都是一个函数
Server.use(path,function(req,res,next){})
const express = require('express'); var server = express(); server.listen(8080); //使用中间件验证注册,参数1:给哪个url路由使用,如果为空,表示会给所有的路由使用;参数2:中间件函数;获取请求,以及做出响应 server.use('path',function(req,res,next){//如果path为空,则对所有路由过滤 console.log('验证数据是否为空'); next();//会执行下一个中间件或者路由 }) server.get('/reg',function(req,res){ res.send('注册成功'); }); server.get('/list',function(req,res){ res.send('这是商品列表'); }) |
- 路由级中间件
Server.use(path,路由器)
- 内置中间件
在express4下只保留了一个内置中间件
server.use(Express.static('目录’));
把静态资源托管到指定的目录,如果浏览器请求静态资源,自动到该目录下查找
- 第三方中间件
Server.use(body.urlencoded({extended:false}))
创建hehe.js文件,创建web服务器,托管静态资源到public下,在public下创建login.html,使用浏览器请求该文件,点击按钮,向服务器发请求
const express = require('express'); const bodyp = require('body-parser'); var server = express(); server.listen(8080); server.use(express.static('public')); server.use(bodyp.urlencoded({ //将post请求的数据格式化为对象 extended:false//不使用扩展的qs模块,而是使用querystring模块,格式化为对象 })); server.post('/mylogin',function(req,res){ console.log(req.body); //格式为对象 res.send('登录成功'); }) |
<h2>这是静态文件</h2> <form method="post" action="mylogin"> 用户名:<input type="text" name="uname"><br> 密码:<input type="passward" name="pwd"><br> <input type="submit"> </form> |
连接MySQL
var connection = mysql.createConnection({
host:’127.0.0.1’,
port:3306,
user:’root’,
password:’’,
database:’数据库名’ //连接后使用的数据库
});//创建连接对象
connection.connect() //建立连接
connection.query(sql,callback) sql是要执行的sql语句,callback回调函数,用于获取sql语句的结果
connection.end() 关闭连接
const mysql = require('mysql'); //引入MySQL模块 var connection = mysql.createConnection({//创建连接对象 host:'127.0.0.1', port:'3306', user:'root', password:'', database:'dang'//连接后使用的数据库 }) connection.connect();//建立连接 connection.query('select * from book',function(err,result){//err可能产生的错误,result执行的结果 if(err) throw err; console.log(result); }); //关闭连接 connection.end(); |
连接池
var pool = mysql.createPool();
//引入MySQL模块 const mysql = require('mysql'); //创建连接池对象 var pool = mysql.createPool({ host:'127.0.0.1', port:'3306', user:'root', password:'', database:'dang',//连接后使用的数据库 connectionLimit:20//设置连接池大小,默认是15 }) pool.query('select * from book',function(err,result){ if(err) throw err; console.log(result); }); |
插入数据(非正规sql语句,只适用于插入)
var obj = { //对象中的属性名必须和表中的列名一致 bid:10, title:'gangtie', author:'dff', price:10, publish:'sha', pubTime:'2020-03-01' } pool.query('insert into book set ?',[obj],function(err,result){ //?代表占位符 if(err) throw err; console.log(result); }) |
修改数据
pool.query('update book set title=? where bid=?',['summer',10],function(err,result){ if(err) throw err; console.log(result); }); |
删除数据
pool.query('delete from book where bid=6',function(err,result){ if(err) throw err; console.log(result); }); |
综合案例:
const express = require('express'); const mysql = require('mysql'); var server = express(); server.listen(8080); server.use(express.static('public'));//托管静态资源到public var pool = mysql.createPool({//创建数据池 host:'127.0.0.1', port:3306, user:'root', password:'', database:'dang' }) server.get('/add',function(req,res){//根据表单提交创建对应路由 var obj = req.query;//获取浏览器传递的数据 console.log(obj); pool.query('insert into book set ?',[obj],function(err,result){ if(err) throw err; if(result.affectedRows > 0){ res.send({code:200,msg:'add suc'}); } }) }); |
<h2>添加数据</h2> <form method="get" action="/add"> <!-- ID:<input type="text" name="bid"><br> --> 标题:<input type="text" name="title"><br> 作者:<input type="text" name="author"><br> 价格:<input type="text" name="price"><br> 出版社:<input type="text" name="publish"><br> 出版时间:<input type="text" name="pubTime"><br> <input type="submit" name=""> </form> |
基础项目用户路由器文件
//用户路由器 const express = require('express'); const pool = require('../pool.js') var router = express.Router(); //用户注册 router.get('/reg',function(req,res){ var obj = req.query;//获取get请求的数据 if(obj.uname==''){//检测值是否为空 res.send({code:401,msg:'uname required'}); return;//阻止往后执行 } if(obj.upwd==''){ res.send({code:402,msg:'upwd required'}); return; } if(obj.phone==''){ res.send({code:403,msg:'phone required'}); return; } if(obj.email==''){ res.send({code:401,msg:'email required'}); return; } pool.query('insert into user set ?',[obj],function(err,result){ if(err) throw err; console.log(result); if(result.affectedRows>0){ res.send({code:200,msg:'suc'}); } }) }) //用户登录 router.post('/login',function(req,res){ var obj = req.body; //console.log(obj); if(obj.uname ==''){ res.send({code:401,msg:'required'}); return; } if(obj.upwd == ''){ res.send({code:402,msg:'required'}); return; } pool.query('select * from user where uname=? and upwd=?',[obj.uname,obj.upwd],function(err,result){ if(err) throw err; if(result.length>0){ res.send({code:200,msg:'login suc'}); }else{ res.send({code:301,msg:'login err'}); } });//查询用户表中是否含有输入的数据 }) //用户修改 router.get('/update',function(req,res){ var obj = req.query; var c = 400;//初始化状态码 for(var key in obj){//遍历对象属性 c ++; //判断属性值是否为空 if(!obj[key]){ res.send({code:c,msg:key+' required'}); return; } } pool.query('update user set uname=?,gender=?,email=?,phone=? where uid=?',[obj.uname,obj.gender,obj.email,obj.phone,obj.uid],function(err,result){ if(err) throw err; if(result.affectedRows>0){//判断是否修改成功 res.send({code:200,msg:'update suc'}) }else{res.send({code:301,msg:'update err'});} }) }) //用户检索 router.get('/detail',function(req,res){ var obj = req.query; if(!obj.uid){ res.send({code:401,msg:'ID required'}); res.end(); } pool.query('select * from user where uid=?',[obj.uid],function(err,result){ if(err) throw err; res.send(result); }) }) //用户删除 router.get('/delete',function(req,res){ var obj = req.query; if(!obj.uid){ res.send({code:401,msg:'ID required'}); return; } pool.query('delete from user where uid=?',[obj.uid],function(err,result){ if(err) throw err; if(result.affectedRows>0){ res.send({code:200,msg:'delete suc'}); }else{ res.send({code:301,msg:'delete err'}); } }) }) //查看用户列表 router.get('/list',function(req,res){ var obj = req.query; if(!obj.pnum){obj.pnum = 1;} if(!obj.count){obj.count = 3;} //将传递的值转为整形 obj.pnum=parseInt(obj.pnum); obj.count=parseInt(obj.count); //计算开始查询的值 var start=(obj.pnum-1)*obj.count; pool.query('select * from user limit ?,?',[start,obj.count],function(err,result){ if(err) throw err; res.send(result); }) }) module.exports = router;//导出路由器 |