目录
包和NPM
查询字符串模块(querystring)
//引入查询字符串模块
const querystring = require('querystring');
//引入查询字符串模块
const querystring = require('querystring');
let str = 'Kw=dell&price=4999';
//解析查询字符串为对象
let obj = querystring.parse(str);
console.log(obj);
//将对象格式化为查询字符串
const str2 = querystring.stringify(obj);
console.log(str2);
URL模块(url)
//引入url模块
const url = require('url');
//引入url模块
const url = require('url');
const str = 'https://editor.csdn.net/md?not_checkout=1&articleId=127028464'
//解析url为对象
let obj = url.parse(str);
console.log(obj);
//将对象格式转换为url
const URL = {
protocol: 'https:',
slashes: true,
auth: null,
host: 'editor.csdn.net',
port: null,
hostname: 'editor.csdn.net',
hash: null,
search: '?not_checkout=1&articleId=127028464',
query: 'not_checkout=1&articleId=127028464',
pathname: '/md',
path: '/md?not_checkout=1&articleId=127028464',
href: 'https://editor.csdn.net/md?not_checkout=1&articleId=127028464'
}
const str2 = url.format(URL)
console.log(str2);
文件模块(fs)
//引入文件模块
const fs = require('fs')
同步异步
查看文件的状态(stat,statSync)
异步无需等待
//引入文件模块
const fs = require('fs')
//查看文件的状态
fs.stat('fs测试文件', (err, state) => {
console.log(err);
console.log(state);
console.log(state.isFile());
console.log(state.isDirectory());
})
同步,必须等待statSync执行完
//引入文件模块
const fs = require('fs')
const result = fs.statSync('fs测试文件')
console.log(result); //true
检测文件是否存在(existsSync)
创建文件(mkdir,mkdirSync)
/**
* 创建目录 异步与同步
*/
fs.mkdir('fs测试mkdir文件', (err) => {
console.log(err);
})
const mkdirSyncResult = fs.mkdirSync('fs测试mkdirSync文件')
console.log(mkdirSyncResult);
读目录(readdir,readdirSync)
/**
* 读取目录 异步与同步
*/
console.log("读取文件异步操作");
fs.readdir('fs测试readdir文件', (err, files) => {
console.log(err);
console.log(files);
})
console.log("读取文件同步操作");
const readResult = fs.readdirSync('fs测试readdir文件')
console.log(readResult);
读文件(readFile,readFileSync)
/**
* 读取文件 异步与同步
*/
const data = fs.readFileSync('练习.txt')
console.log(data.toString()); //同步代码需要转换为字符
fs.readFile('练习.txt', (data2) => {
console.log(data2);
})
删除目录(rmdir,rmdirSync)
/**
* 删除目录 异步与同步
*/
fs.rmdir('fs测试mkdir文件', (err) => {
console.log(err);
})
console.log("异步,我先执行");
const rmdirSyncResult = fs.rmdirSync('fs测试mkdirSync文件')
console.log(rmdirSyncResult);
console.log("同步,我后执行");
删除文件(unlink,unlinkSync)
/**
* 删除文件 异步与同步
*/
if (fs.existsSync("练习.txt")) {
fs.unlink('练习.txt', (err) => {
console.log(err);
console.log("************************");
})
}
const link = fs.unlinkSync('练习.txt')
console.log(link);
删除文件,记得要拼接删除路径
const fs = require('fs');
//首先检测目录是否存在
if (fs.existsSync('fs练习删除文件夹')) {
console.log("存在");
//目录存在读取目录下的文件,并返回一个数组
const arr = fs.readdirSync('fs练习删除文件夹')
console.log(arr);
//循环删除文件
for (let index = 0; index < arr.length; index++) {
//这里注意此时执行目录为删除目录的上一级,需要拼接上一级目录才可删除
const err = fs.unlinkSync('fs练习删除文件夹/' + arr[index])
console.log(err);
}
const arr2 = fs.readdirSync('fs练习删除文件夹')
console.log(arr2);
}
递归删除既有文件又有文件夹的文件
//删除文件夹与文件
function delDir(path) {
let arr = []
if (fs.existsSync(path)) {
//读取目录下的文件
arr = fs.readdirSync(path);
console.log(arr);
for (let i = 0; i < arr.length; i++) {
curpath = path + '/' + arr[i]
if (fs.statSync(curpath).isDirectory()) {
delDir(curpath)
} else {
fs.unlinkSync(curpath)
}
}
fs.rmdirSync(path)
}
}
清空写入(writeFile,writeFileSync)
/**
* 创建文件 异步与同步
*/
fs.writeFile('fs创建文件.txt', '这里是写入的内容,如果文件已存在,则替换', (err) => {
console.log(err);
if (err) throw err;
console.log("文件写入成功");
})
const fsWriteFileSync = fs.writeFileSync('fs同步写文件.txt', '如果文件中内容已存在,则将内容清空,写入')
console.log(fsWriteFileSync);
追加写入(appendFile,appendFileSync)
/**
* 追加写入 异步与同步
*/
fs.appendFile('fs追加文本.txt', '追加内容,不会清空重写\n', (err) => {
if (err) throw err;
console.log("追加成功");
})
const fsAppendFileSync = fs.appendFileSync('fs追加文本.txt', '同步追加内容')
console.log("我是否成功了" + fsAppendFileSync);
文件流(createReadStream,createWriteStream)
拷贝读取快,比拷贝api快
node中文件流是分段读取的,速度很快。
// 文件流需要引入fs模块
const fs = require('fs')
//创建一个可读取的流
let readStream = fs.createReadStream('新建 文本文档.txt')
//事件:监听是否有数据流入到内存
//data:事件名称 监听数据的事件 不能够随意更改
readStream.on('data', (chunk) => {
console.log(chunk.toString()); //读取非txt文件不需要toString()
})
// 文件流需要引入fs模块
const fs = require('fs')
//创建可读取的流
let readStream = fs.createReadStream('新建 文本文档.zip');
//创建可写入的流
let writeStream = fs.createWriteStream('new.zip')
//把读取的流通过管道添加到写入流
readStream.pipe(writeStream)
拷贝文件(copyFile,copyFileSync)
// 文件流需要引入fs模块
const fs = require('fs')
//拷贝文件
fs.copyFileSync('新建 文本文档.zip', 'new2.zip')
fs.copyFile('新建 文本文档.zip', 'new2.zip', (err) => {
console.log(err);
})
HTTP协议
浏览器和web服务器之间的通信协议
(1)通用头信息
(2)响应头信息
(3)请求头信息
(4)请求主体
HTTP模块(http)
http 模块是 Node.js 官方提供的、用来创建 web 服务器的模块。通过 http 模块提供的 http.createServer() 方法,就能方便的把一台普通的电脑,变成一台 Web 服务器,从而对外提供 Web 资源服务。
服务器和普通电脑的区别在于,服务器上安装了 web 服务器软件,例如:IIS、Apache 等。通过安装这些服务器软件,就能把一台普通的电脑变成一台 web 服务器。
在 Node.js 中,我们不需要使用 IIS、Apache 等这些第三方 web 服务器软件。因为我们可以基于 Node.js 提供的 http 模块,通过几行简单的代码,就能轻松的手写一个服务器软件,从而对外提供 web 服务。
在开发期间,自己的电脑既是一台服务器,也是一个客户端,为了方便测试,可以在自己的浏览器中输入 127.0.0.1 这个 IP 地址,就能把自己的电脑当做一台服务器进行访问了。
在开发测试期间, 127.0.0.1 对应的域名是 localhost,它们都代表我们自己的这台电脑,在使用效果上没有任何区别。
计算机中的端口号,就好像是现实生活中的门牌号一样。通过门牌号,外卖小哥可以在整栋大楼众多的房间中,准确把外卖送到你的手中。
每个端口号不能同时被多个 web 服务占用。
在实际应用中,URL 中的 80 端口可以被省略。
创建最基本的 web 服务器
步骤:
①导入 http 模块
②创建 web 服务器实例
③为服务器实例绑定 request 事件,监听客户端的请求
④启动服务器
// 1.导入 http 模块。
const http = require('http');
// 2.创建 web 服务器实例。
const server = http.createServer();
// 3.为服务器实例绑定 request 事件,监听客户端请求。
server.on('request', function(req, res) {
console.log('someone visit our web server');
});
// 4.启动服务器
server.listen(8080, function() {
console.log('server runing at http://127.0.0.1:8080');
});
req 请求对象
只要服务器接收到了客户端的请求,就会调用通过 server.on() 为服务器绑定的 request 事件处理函数。
如果想在事件处理函数中,访问与客户端相关的数据或属性,可以使用如下的方式:
const http = require('http');
const server = http.createServer();
// req请求对象,包含了与客户的相关的数据和属性
server.on('request', req => {
// req.url 是客户端请求的 URL地址
const url = req.url;
// req.method 是客户端请求的 method 类型
const method = req.method;
const str = `Your request url is ${url},and
request url is ${method}`;
console.log(str);
});
server.listen(8080, function() {
console.log('server runing at http://127.0.0.1');
});
res请求对象
// res是响应对象,它包含了与服务器相关的数据和属性
// 调用 res.end() 方法,向客户端响应一些内容。
res.end(str);
也可以调用write做响应,但后面必须跟上end
//设置响应的内容
res.write('<h2>这是我的第一个网页</h2>')
//结束并发送响应
res.end();
//导入http模块
const http = require('http')
//向服务器发送请求
//通过回调函数获取响应结果
http.get('http://www.weather.com.cn/data/sk/101010100.html', (res) => {
//res响应的对象
// 响应的状态码
console.log(res.statusCode);
//获取响应的结果
//事件:监听是否有数据过来
res.on('data', (chunk) => {
console.log(chunk.toString());
})
})
//引入http模块
const http = require('http')
//创建web服务器
let app = http.createServer();
//监听端口
app.listen(8082);
//事件:服务器监听是否有请求
//通过回调函数做出响应
//如果想让服务器做出响应,回调函数必须有两个参数 req和res 根据req返回res
app.on('request', (req, res) => {
console.log("有请求进来了");
console.log(req.url);
console.log(req.method);
console.log(req.headers);
/**
* 状态码为200,响应
*/
//防止乱码 设置响应文件类型与编码
// res.writeHead(200, {
// 'Content-type': 'text/html;charset=utf-8'
// })
//设置响应的内容
res.write('<h2>这是我的第一个网页</h2>')
/**
* 状态码为3**,跳转网页
* 跳转到另一个URL
*/
res.writeHead(302, {
//3** 要有Location属性
Location: 'https://www.baidu.com'
})
//结束并发送响应
res.end();
})
//导入http模块
const http = require('http')
//导入fs模块
const fs = require('fs')
//导入gzip模块
const zlib = require('zlib');
//创建web服务器
let server = http.createServer();
//监听浏览器的请求
server.on('request', (req, res) => {
res.writeHead(200, {
'Content-type': 'text/html;charset=utf-8'
})
//获取请求路径
let reqUrl = req.url
if (reqUrl == '/index.html') {
console.log("我是首页");
res.write("我是首页");
res.end();
} else if (reqUrl == '/about.html') {
//读取文件,响应到网页上
// const readFile = fs.readFileSync('响应读取.html');
// res.write(readFile);
/**
* 使用gzip压缩压缩大文件传输
*/
//1.告诉浏览器使用的是哪种压缩方式
res.writeHead(200, {
'Content-Encoding': 'gzip'
})
//2.创建gzip压缩
let gzip = zlib.createGzip()
//创建可读取的流,通过管道添加到压缩中,再把压缩通过管道响应到浏览器端
fs.createReadStream('响应读取.html').pipe(gzip).pipe(res)
//这里已经响应过去了,就不能加end(),否则报错
console.log("读取成功");
// res.end()
} else if (reqUrl == '/') {
res.writeHead(302, {
location: '/index.html'
})
res.end()
} else {
res.writeHead(404);
res.write("NOT Found ")
res.end()
}
})
server.listen(8083)
Zlib压缩(zlib)
创建压缩(createDeflate,createGzip)
使用压缩的再次打开会在缓存中打开
//2.创建gzip压缩
let gzip = zlib.createGzip()
//创建可读取的流,通过管道添加到压缩中,再把压缩通过管道
//响应到浏览器端
fs.createReadStream('响应读取.html').pipe(gzip).pipe(res)
//这里已经响应过去了,就不能加end(),否则报错
express框架
介绍
基于node.js平台,快速,开放,极简的web开发框架
安装
//声明package.json文件
npm init -y
//安装express包
npm install express
搭建服务器
//引入express包
const express = require('express')
//创建web服务器
let app = express();
//监听端口
app.listen(8083)
路由(响应对象,请求对象)
//路由:根据请求URL和方法做出响应
//get /login
app.get('/login', (req, res) => {
//req请求的对象
//res响应的对象
res.send('<h2>登录成功</h2>')
})
//请求方法 get /list 响应文件
app.get('/list', (req, res) => {
//__dirName为当前文件的绝对路径
res.sendFile(__dirname + '/响应读取.html')
})
//请求方法get /study 跳转页面
app.get('/study', (req, res) => {
res.redirect('https://www.baidu.com')
})
app.get('/reg', (req, res) => {
//获取查询字符串,并解析为对象
//express已经分装好了查询字符串属性 不能用以前的查询字符串属性
console.log(req.query);
console.log(req.url);
res.send('注册成功' + req.query + req.url)
})
路由传参(params)
params:获取路由传参的数据,格式化对象
//get /package 动态路由
app.get('/package/:pname', (req, res) => {
//获取路由传参的数据
console.log(req.params);
res.send(`这是${req.params.pname}包的详细介绍`)
})
app.get('/shopping/:lid/:price', (req, res) => {
res.send(`
编号:${req.params.lid} <br>
价格:${req.params.price}
`)
})
post请求
//引入express模块
const express = require('express');
//引入查询字符串模块
const queryString = require('querystring')
//创建web服务器
let app = express();
//监听端口
app.listen(8083);
//
app.get('/login', (req, res) => {
console.log(__dirname);
console.log("执行成功");
res.sendFile(__dirname + '/login.html')
})
app.post('/mylogin', (req, res) => {
//获取post请求的数据
//事件:监听是否有数据、
console.log("执行了");
req.on('data', (chunk) => {
console.log(chunk.toString());
let obj = queryString.parse(chunk.toString())
console.log(obj);
})
res.send("登录成功")
})
路由器
app.js入口文件
//引入express模块
const express = require('express')
//创建web服务器
let app = express();
//监听端口
app.listen(8083)
//引入用户路由器
const userRouter = require('./routers/user')
//引入商品列表路由器
const productRouter = require('./routers/product')
//引入首页路由器
const indexRouter = require('./routers/index')
//使用路由器,给路由器下的每个路由器添加前缀
// /login /user/login
app.use('/user', userRouter)
app.use('/product', productRouter)
app.use('/', indexRouter)
index模块
//引入express模块
const express = require('express')
//创建路由器对象
let router = express.Router();
//向路由器中挂载路由对象
router.get('/index', (req, res) => {
res.send("登录界面")
})
module.exports = router;
用户模块
//引入express模块 路由器由express提供
const express = require('express')
//创建路由器对象
let router = express.Router();
//往路由器中挂载路由
/**
* get /login
*/
router.get('/login', (req, res) => {
res.writeHead(200, {
'Content-type': 'text/html;charset=utf-8'
})
res.end('用户登录')
})
//导出路由对象
module.exports = router;
中间件
浏览器向服务器发请求,中间件可以拦截(过滤)请求,最终给路由提供服务,分为:应用级中间件、路由级中间件、内置中间件、第三方中间件、错误处理中间件。
应用级中间件
//引入express模块
const express = require('express');
//创建web服务器
let app = express();
//监听端口
app.listen(8083);
//添加中间件,拦截对URL为/list的请求
app.use('/list', (req, res, next) => {
console.log('拦截到了对/list的请求');
console.log(req.query);
//如果不满足条件,否则执行下一个中间件,或者路由
if (req.query.username !== "root") {
res.send("没有权限");
} else {
next();
}
})
//获取后台数据的路由
app.get('/list', (req, res) => {
res.end("这是后台的数据")
})
不要忘了中间件中的next参数
/**
* 中间件练习
* 创建购物车的路由, get/shopping,传递商品的价格price 在中间打九折,最后在路由中响应。
*/
app.use("/shopping", (req, res, next) => {
console.log(req.query)
req.query.price = req.query.price * 0.5;
next();
})
app.get("/shopping", (req, res) => {
res.send("商品价格为" + req.query.price);
})
路由级中间件
内置中间件
/**
* 内置中间件
* 托管静态资源到public目录
*/
app.use(express.static('public'))
//引入bodyParser模块 用于解析请求体数据为对象
const bodyParser = require('body-parser')
//引入compression模块 对所有请求进行压缩
const compression = require('compression');
//对所有请求进行压缩 比如压缩大文件
app.use(compression());
/**
* 内置中间件
* 托管静态资源到public目录
*/
app.use(express.static('public'))
//使用body-parser 中间件
app.use(bodyParser.urlencoded({
extended: false //内部解析为对象使用querystring模块 true使用qs模块
}))
mysql模块
初始化
//初始化
npm init -y
//安装mysql包
npm install mysql
mysql普通连接
//引入mysql模块
const mysql = require('mysql');
//创建连接对象
let connection = mysql.createConnection({
host: '127.0.0.1',
port: '23306',
user: 'root',
password: '0071hanxiaolei',
database: 'atguigudb'
})
//执行连接
connection.connect();
mysql连接池连接
//引入mysql模块
const mysql = require('mysql');
//创建连接池对象
let pool = mysql.createPool({
host: '127.0.0.1',
port: '23306',
user: 'root',
password: "0071hanxiaolei",
database: 'atguigudb',
//创建连接池数量 默认数量为15
connectionLimit: 15
})
//执行SQL命令
pool.query('SELECT * FROM emp', (err, result) => {
if (err) throw err;
console.log(result);
})
mysql语句
//执行sql语句
connection.query('SELECT * FROM emp where ?' [5], (err, result) => { //用?号代替5,防止sql注入 '5' OR 1=1
if (err) throw err;
console.log(result);
})
//插入数据
connection.query('INSERT INTO emp VALUES(?,?,?,?,?)', ['8', '王二小', '1999-07-30', 3255, 3003], (err, result) => {
if (err) throw err;
console.log(result);
})
let emp = {
id: '9',
ename: "王八蛋2",
joindate: '2001-04-20',
salary: 7000,
bonus: 3000,
}
//定义插入数据
connection.query('INSERT INTO emp SET ?', [emp], (err, result) => {
if (err) throw err;
console.log(result);
})
这种方法要注意
练习
//引入express模块
const express = require('express');
//引入mysql模块
const mysql = require('mysql');
//创建mysql连接池
let pool = mysql.createPool({
host: '127.0.0.1',
port: '23306',
user: 'root',
password: '0071hanxiaolei',
database: 'atguigudb',
//创建连接池数量
connectionLimit: 15
})
//创建web服务器
let app = express();
app.listen(8083);
//添加中间件 托管静态资源 注意括号中写的什么,不能直接写文件名称
app.use(express.static('public'))
//请求
app.get('/login', (req, res) => {
let obj = req.query;
pool.query('INSERT INTO emp SET ?', [obj], (err, result) => {
if (err) throw err;
console.log(res);
})
req.on('data', (chunk) => {
console.log(chunk.toString());
})
res.send("完成")
})
NPM NPX
编写接口
//引入模块
const express = require('express')
const mysql = require('mysql')
//创建web服务器
let app = express();
app.listen(8083);
//创建mysql连接
const pool = mysql.createPool({
host: '127.0.0.1',
port: '23306',
user: 'root',
password: '0071hanxiaolei',
database: 'atguigudb',
connectionLimit: 15
})
//1.获取员工数据的路由 (get /v1/emp)
app.get('/v1/emp', (req, res) => {
//获取请求中已查询字符串传递的数据
let obj = req.query;
//如果页码为空,设置默认为1
if (!obj.pho) {
obj.pho = 1;
}
//如果页码为空,设置默认为5
if (!obj.count) {
obj.count = 5
}
console.log(obj);
//计算开始查询的值 计算方式:(页数-1)*每页数量
let start = (obj.pho - 1) * obj.count;
//将每页的数据量转换为数值型
let count = parseInt(obj.count)
//执行mysql语句
pool.query('SELECT * FROM emp limit ?,?', [start, count], (err, result) => {
// if (err) throw err;
if (err) {
//如果执行sql命令错误,响应服务端错误
res.send({
code: 500,
msg: 'serve error'
})
//不能在往后执行了,跳出当前函数
return
}
//获取sql命令执行的结果
// console.log(result);
// res.send(result);
res.send({
code: 200,
msg: 'OK',
data: result
})
})
})