Node.js 是一个基于 V8 引擎的 JavaScript 运行时(运行环境)
** 注意:**
浏览器是 JavaScript 的前端运行环境
Node.js 是 JavaScript 的后端运行环境
Node.js 中无法调用 DOM、BOM 等浏览器的 API
基于 Node.js 有很多强大的工具和框架
① Express—Web 应用
② Electron—跨平台的桌面应用
③ restify—快速构建 API 接口
④ 读写操作数据库、创建实用的命令行工具辅助前端开发
⑤ 等等
** 注意:**
// 1.引入http模块
const http = require("http");
// 2.创建服务器
const server = http.createServer();
// 3.监听request事件
server.on("request", (req, res) => {
// 3.1 req是请求对象,包含与客户端相关的数据与属性
// 如:req.url:客户端请求的地址;req.method:请求类型
const url = req.url;
const method = req.method;
// 3.2 res是相应对象,包含与服务端相关的数据与属性
// 如:res.end(str):向客户端发送指定的内容并结束这次请求的处理过程
res.setHeader('Content-Type','text/html; charset=utf-8')
res.end('hello')
});
// 4.启动服务器
server.listen(8080, () => {
console.log("http server running at http://127.0.0.1:8080");
});
解决一个复杂问题时,自顶向下把系统分成若干模块的过程。
对于整个系统来说,模块是课组合、分解和更换的单元。
和函数作用域类似,只能再当前模块内被访问。
防止全局变量的污染。
内置模块是 Node.js 官方提供的。
例如:fs,path,http 等等。
用户自己创建的.js 文件。
由第三方开发出来的模块,使用前需要先下载。
第三方模块也叫做包。
在每个.js 自定义模块中都有一个 module 对象,它存储了和当前模块有关的信息.
打印 module 的一个例子
Module {
id: '.',
path: 'E:\\工作\\node学习',
exports: {},
filename: 'E:\\工作\\node学习\\1.js',
loaded: false,
children: [],
paths: [
'E:\\工作\\node学习\\node_modules',
'E:\\工作\\node_modules',
'E:\\node_modules'
]
}
将模块内的成员共享出去,供外界使用。默认情况为{}
外界用 require()方法导入自定义模块时,得到的就是 module.exports 这个对象。
exports 指向的就是 module.exports 这个对象。
** 注意:**
将模块导出的对象始终为 module.exports 这个对象。
Node.js 遵循了 CommonJS 模块化规范。
规定:
即第三方模块。包是基于内置模块封装出来的,提供了更高级、更方便的 API,极大的提高了开发效率。
https://www.npmjs.com/ 查看包 https://registry.npmjs.org/ 下载包
随着 Node.js 安装包一起安装。
npm install 包名称
npm i 包名称
npm uninstall 包名称
初次安装包出现的文件:
npm 规定,在项目根目录中,必须提供一个叫做 package.json 的包管理配置文件。
package.json:记录与项目有关的一些配置信息。
例如:
npm init -y
npm i 包名 -D
npm install 包名 --save-dev
淘宝 NPM 镜像服务器
npm config get registry
npm config set registry=https://registry.npm.taobao.org/
npm config get registry
nrm 是用来切换镜像源的
npm i nrm -g
nrm ls
nrm use taobao
npm i 包名
npm i 包名 -D
npm i 包名 -g
一个例子——包含有的功能:
// 1.导入
const tools = require("./sunny-tools");
// 2.使用
const dt = tools.dateFormat(new Date());
console.log(dt);
// 1.导入
const tools = require("./sunny-tools");
// 2.使用
const htmlStr = '你好小黄
';
const str = tools.htmlEscape(htmlStr);
console.log(str);
// 1.导入
const tools = require("./sunny-tools");
// 2.使用
const rawHTML = tools.htmlUnEscape(str);
console.log(rawHTML);
初始化包的结构
① 新建 sunny-tools 文件
② 在 sunny-tools 文件中新建:
③ 在 sunny-tools 文件中新建 src 文件夹,再在 src 中新建:
初始化 package.json 文件
{
"name":"sunny-tools",
"version":"1.0.0",
"main":"index.js",
"description": "提供了格式化时间,HTMLEscape的功能",
"keywords": ["sunny","dataFomat","escape"],
"license": "ISC"
}
const date = require("./src/dateFormat");
const escape = require("./src/htmlEscape");
module.exports = {
...date,
...escape,
};
function dateFormat(dataStr) {
const dt = new Date(dataStr);
const y = dt.getFullYear();
const m = padZero(dt.getMonth() + 1);
const d = padZero(dt.getDay());
const hh = padZero(dt.getHours());
const mm = padZero(dt.getMinutes());
const ss = padZero(dt.getSeconds());
return `${y}-${m}-${d} ${hh}:${mm}:${ss}`;
}
// 补零函数
function padZero(n) {
return n > 9 ? n : "0" + n;
}
module.exports = {
dateFormat,
};
// 转义HTML字符
function htmlEscape(htmlstr) {
return htmlstr.replace(/<|>|"|&/g, (match) => {
switch (match) {
case "<":
return "<";
case ">":
return ">";
case '"':
return """;
case "&":
return "&";
}
});
}
// 还原HTML字符
function htmlUnEscape(str) {
return str.replace(/<|>|"|&/g, (match) => {
switch (match) {
case "<":
return "<";
case ">":
return ">";
case """:
return '"';
case "&":
return "&";
}
});
}
module.exports = {
htmlEscape,
htmlUnEscape,
};
//查看所有的镜像源
nrm ls
//将下包的镜像源切换到 npm 镜像
nrm use npm
npm login
//根据提示输入用户名、密码
发布包
切换到发布包的根目录下(包名要唯一)
npm publish
删除已发布的包
npm unpublish 包名 --force
./
或../
的路径表示符。如果没有则 node 把它当作内置模块或者第三方模块加载。基于 Node.js 平台,快速、开放、极简的 Web 开发框架。
通俗:Express 和 Node.js 内置的 http 模块类似,专门用来创建 Web 服务器
下载 express
npm install express
// 1. 导入express
const express = require("express");
// 2. 创建 web 服务器
const app = express();
// 3. 调用app.listen(端口号,启动成功的回调函数),启动服务器
app.listen(80, () => {
console.log("express server running at http://172.0.0.1");
});
app.use(express.static('public'))
现在可以访问 public 目录下所有文件(假设 public 有 css.js,index.js,index.html)
http://localhost:3000/css.js
http://localhost:3000/index.js
http://localhost:3000/index.html
例子:
const express = require("express");
const app = express();
app.use(express.static("./clock"));
app.listen(80, () => {
console.log("express server running at http://127.0.0.1");
});
const express = require("express");
const app = express();
app.use(express.static("./files"));
app.use(express.static("./clock"));
app.listen(80, () => {
console.log("express server running at http://127.0.0.1");
});
//files和clock文件下都有clock.html
//访问http://127.0.0.1/clock.html 出现的是files下的clock.html
app.use('/public',express.static('public'))
下载
npm i -g nodemon
使用
原来是node app.js
,下载改为
nodemon app.js
app.METHOD(PATH,HANDLER)
app.get("/user", (req, res) => {
res.send({ name: "zs", age: 20, gender: "男" });
});
app.post("/user", (req, res) => {
res.send("请求成功");
});
// 1. 导入express
const express = require("express");
// 2. 创建 web 服务器
const app = express();
//挂载路由
app.get("/", (req, res) => {
res.send('hello');
});
app.post("/", (req, res) => {
res.send("请求成功");
});
// 3. 调用app.listen(端口号,启动成功的回调函数),启动服务器
app.listen(80, () => {
console.log("express server running at http://127.0.0.1");
});
express.Router()
函数创建路由对象module.exports
向外共享路由对象app.use()
函数注册路由模块① 创建路由模块
// 1.导入express
const express = require("express");
// 2.创建router对象
const router = express.Router();
// 3. 挂载具体的路由对象
router.get("/user/list", (req, res) => {
res.send("Get user list");
});
router.post("/user/add", (req, res) => {
res.send("Add new user");
});
// 4. 向外导出路由对象
module.exports = router;
② 注册路由模块
//1.到哦如路由模块
const userRouter = require(./ruoter/user.js)
2.使用app.use()注册路由模块
app.use(userRouter)
//1.到哦如路由模块
const userRouter = require(./ruoter/user.js)
2.使用app.use()注册路由模块
app.use('/api',userRouter)
const express = require("express");
const app = express();
app.get("/", function(req,res,next){
next()
});
app.listen(3000);
注意:
中间件函数的形参列表中必须包含next
参数,而路由处理函数中只包含 req 和 res 4. next()函数作用
next函数
是实现多个中间件连续调用的关键,他表示把流转关系转交给下一个中间件或路由
const express = require("express");
const app = express;
// 定义一个最简单的中间件函数
const mw = function (req, res, next) {
console.log("这是最简单的中间件");
next();
};
app.listen(80, () => {
console.log("http://127.0.0.1");
});
const express = require("express");
const app = express();
// 定义一个最简单的中间件函数
const mw = function (req, res, next) {
const time = Date.now();
// 为req挂载自定义属性,从而把time共享给后面的路由
req.startTime = time;
next();
};
// 将mw注册为全局生效的中间件
app.use(mw);
app.get("/", (req, res) => {
res.send("Home page." + req.startTime);
});
app.get("/user", (req, res) => {
res.send("User page." + req.startTime);
});
app.listen(80, () => {
console.log("http://127.0.0.1");
});
app.use(中间件函数)
即可定义一个全局生效的中间件// 定义一个最简单的中间件函数
const mw = function (req, res, next) {
console.log("这是最简单的中间件");
next();
};
// 将mw注册为全局生效的中间件
app.use(mw);
例子:
const express = require("express");
const app = express();
// 定义一个最简单的中间件函数
const mw = function (req, res, next) {
console.log("这是最简单的中间件");
next();
};
// 将mw注册为全局生效的中间件
app.use(mw);
app.get("/", (req, res) => {
console.log("调用了'/'这个路由");
res.send("Home page.");
});
app.get("/user", (req, res) => {
console.log("调用了'/user'这个路由");
res.send("User page.");
});
app.listen(80, () => {
console.log("http://127.0.0.1");
});
app.use()
。客户端请求到达服务器之后,会按照中间件的先后顺序
一次执行调用const express = require("express");
const app = express();
app.use(function (req, res, next) {
console.log("中间件1");
next();
});
app.use(function (req, res, next) {
console.log("中间件2");
next();
});
app.get("/", (req, res) => {
res.send("Home page.");
});
app.get("/user", (req, res) => {
res.send("User page.");
});
app.listen(80, () => {
console.log("http://127.0.0.1");
});
app,use
定义的中间叫做局部生效的中间件,示例:const express = require("express");
const app = express();
//定义中间件1
const mw1 = function (req, res, next) {
console.log("这是中间件函数1");
next();
};
// mw1在“/”局部生效
app.get("/", mw1, (req, res) => {
res.send("Home page");
});
// mw1对“/user”无影响
app.get("/user", (req, res) => {
console.log("mw1未生效");
res.send("User page");
});
app.listen(80, () => {
console.log("http://127.0.0.1");
});
const express = require("express");
const app = express();
//定义中间件1
const mw1 = function (req, res, next) {
console.log("这是中间件函数1");
next();
};
// 定义中间件2
const mw2 = function (req, res, next) {
console.log("这是中间件函数2");
next();
};
// 使用多个局部中间件,方式一
app.get("/my1", mw1, mw2, (req, res) => {
res.send("My1 page");
});
// 使用多个局部中间件,方式二
app.get("/my2", [mw1, mw2], (req, res) => {
res.send("My2 page");
});
app.listen(80, () => {
console.log("http://127.0.0.1");
});
next()
函数① 应用级别的中间件
② 路由级别的中间件
③ 错误级别的中间件
④ Express 内置的中间件
⑤ 第三方的中间件
通过app.use()
或app.get()
或app.post()
,绑定到 app 实例上的中间件,叫做应用级别的中间件。
示例:
//1.
app.use(function (req, res, next) {
console.log("中间件1");
next();
});
//2.
const mw1 = function (req, res, next) {
console.log("这是中间件函数1");
next();
};
app.get("/", mw1, (req, res) => {
res.send("Home page");
});
绑定到express.Router()
实例上的中间件,叫做路由级别的中间件。
用法和应用级别的中间件没有区别。
但,应用级别中间件绑定到 app 实例上,路由级别中间件绑定到 router 实例上。
示例:
const app = express()
const router = express.Router()
// 路由级别中间件
router.use(function(req,res,next){
console.log("Time:",Date.now());
next();
})
app.use('/',router)
(err,req,res,next)
示例:
app.get("/", (req, res) => {
throw new Error("服务器内部发生了错误!");
res.send("Home page");
});
app.use(function (err, req, res, next) {
console.log("发生了错误:" + err.message);
res.send("Error!" + err.message);
});
注意:错误级别的中间件必须注册在所有路由之后!
express.static
:快速托管静态资源的内置中间件,例如:HTML 文件、图片、CSS 样式等express.json
:解析 JSON 格式的请求体数据(4.16+)express.urlencoded
:解析 URL-encoded 格式的请求体数据(4.16+)//配置解析application/json格式数据的内置中间件
app.use(express.json())
//配置解析application/x-www-form-urlencoded 格式数据的内置中间件
app.use(express.urlencoded({extended:false}))
示例:
const express = require("express");
const app = express();
// 设置解析表单JSON数据的中间件
app.use(express.json());
// 设置解析application/x-www-form-urlencoded 格式的中间件
app.use(express.urlencoded({ extended: false }));
app.post("/user", (req, res) => {
// 在服务器使用 req.body 接收客户端发送过来的请求体
// 默认情况下,若不配置解析表单数据的中间件,req.body 默认等于undefined
console.log(req.body);
res.send("ok");
});
app.post("/book", (req, res) => {
// 在服务器使用 req.body 接收客户端发送过来的请求体
console.log(req.body);
res.send("ok");
});
app.listen(80, () => {
console.log("Express server running at http://172.0.0.1");
});
由第三方开发出来的中间件,按需下载并配置第三方中间件,从而提高开发效率
npm install 中间件名
require
导入中间件app.use
注册并使用中间件例子:模拟一个类似与express.urlencoded
这样的中间件,来解析 POST 提交到服务器的表单数据。
① 定义中间件
② 监听 req 的 data 事件
③ 监听 req 的 end 事件
④ 使用 qurestring 模块解析请求体数据
⑤ 将解析出来的数据对象挂载为 req.body
⑥ 将自定义中间件封装为模块
注意:
Node.js
内置了一个qureystring
模块,专门用来处理查询字符串。通过这个模块提供的 parse()函数,把查询字符串解析成对象格式代码:
// 引入qureysrting模块
const qs = require("qs");
const bodyParser = (req, res, next) => {
// 定义str,存储客户端发送过来的数据
let str = "";
// 监听req的data事件
req.on("data", (chunk) => {
str += chunk;
});
// 监听req的end事件
req.on("end", () => {
// 这时在str为完整数据
console.log(str);
// TODO:把字符串格式的请求体数据,解析成对象格式
const body = qs.parse(str);
console.log(body);
// 挂载为req.body
req.body = body;
next();
});
};
module.exports = bodyParser;
const express = require("express");
const app = express();
// 导入自己封装的my-body-parser
const myBodyParser = require("./10my-body-parser");
app.use(myBodyParser);
app.post("/user", (req, res) => {
res.send(req.body);
});
app.listen(80, () => {
console.log("Express server running at http://172.0.0.1");
});
① 创建 express 服务器
② 创建 API 路由模块(在此编写接口)
router.get("/get", (req, res) => {
// 通过 req.body 获取客户端通过查询字符串,发送到服务器的数据
const query = req.query;
// 调用 res.send() 方法,向客户端响应处理的结果
res.send({
status: 0, //0成功,1失败
msg: "GET请求成功", //状态描述
data: query, //需要响应给客户端的数据
});
});
注意:一般都要配置解析表单数据的中间件
router.post("/post", (req, res) => {
const body = req.body;
res.send({
status: 0,
msg: "POST请求成功",
data: body,
});
});
CORS
跨域资源共享JSONP
:只支持GET
cors中间件
解决跨域npm install cors
const cors = require('cors')
app.use(cors())
配置中间件Access-Control-Allow-Origin:
res.setHeader('Access-Control-Allow-Headers',参数)
Access-Control-Allow-Headers
对额外的请求头进行声明,否则这次请求会失败GET
、POST
、HEAD
请求。OPTION
请求进行预检,以获取服务器是否允许该实际请求,所以这一次的 OPTION 请求成为“预检请求”。服务器响应预检请求后,才会发送真正的请求,并且携带真实数据。
标签的src
属性,请求服务器上的数据,同时,服务器返回一个函数的调用。这种请求数据的方式叫做 JSONP
标签进行解析执行app.get("/api/jsonp", (req, res) => {
// TODO:定义具体的JSONP接口
const funcName = req.query.callback;
const data = { name: "zs", age: 22 };
const scriptStr = `${funcName}(${JSON.stringify(data)})`;
res.send(scriptStr);
});
数据库:组织、存储和管理数据的仓库
数据结构分为:数据库(database)
、数据表(table)
、数据行(row)
、字段(field)
实际开发库、表、行、字段关系:
① 一般每个项目对应一个数据库
② 不同数据存储到不同表
③ 每个表存储数据由字段决定
④ 表中的行代表每一条具体的数据
MySQL Sever:专门用来提供数据存储和服务的软件
MySQL Workbentch:可视化的 MySQL 管理工具
Navicat:可视化的 MySQL 管理工具
一些 sql 语句:
-- 1.筛选
select * from users;
select username,password from users;
-- 2.插入
insert into users (username,password) values ('sunny','789123');
-- 3.更新
update users set password='888888' where id=3;
update users set password='888111',status=1 where id=3;
-- 4.删除
-- delete from users where id=4;
-- 5.where
select * from users where status=1;
select * from users where id>=2;
-- <> !=不等于
select * from users where username<>'ls';
select * from users where username!='ls';
-- 6.and \ or
select * from users where status=0 and id<2;
select * from users where status=0 or id<2;
-- 7.order by 排序
-- 升序ASC或者省略
select * from users order by status;
select * from users order by status asc;
-- 降序
select * from users order by status desc;
-- 多重排序
select * from users order by status desc,username asc;
-- 8.count(*)函数
-- 统计状态为0的条目数
select count(*) from users where status=0;
-- 9.as 设置别名
select count(*) as total from users where status=0;
select username as uname,password as upwd from users;
npm i mysql
// 1.导入mysql模块
const mysql = require("mysql");
// 2.建立与MySQL数据库的连接
const db = mysql.createPool({
host: "127.0.0.1", //数据库的IP地址
user: "root",
password: "root",
database: "mydb_01", //操作数据库的名字
});
// 测试mysql模块能否正常工作
// db.query()函数,指定要执行的SQL语句,通过回调函数拿到结果
db.query("select 1", (err, res) => {
if (err) return console.log(err.message);
console.log(res);
});
// 查询数据
// select得到的结果为数组
const sql1 = "select * from users";
db.query(sql1, (err, res) => {
if (err) return console.log(err.message);
console.log(res);
});
// 插入数据
// insert into 得到的结果为对象
const newUser = { username: "小红花", password: "456123" };
const sql2 = "insert into users (username,password) values (?,?) ";
db.query(sql2, [newUser.username, newUser.password], (err, res) => {
if (err) return console.log(err.message);
// affectedRows 影响的行数
if (res.affectedRows === 1) {
console.log("插入数据成功");
}
});
由于 cookie 存储在浏览器中,而且浏览器也提供了读写 cookie 的 API,因此 cookie 很容易被伪造,不具有安全性
npm i express-session
// 1. 导入session中间件
var session = require("express-session");
// 2. 配置 session 中间件
app.use(
session({
secret: "sunny learn", //secret可为任意字符串
resave: false, //固定写法
saveUninitialized: true, //固定写法
})
);
app.post("/api/login", (req, res) => {
// 判断用户提交的登陆信息是否正确
if (req.body.username !== "admin" || req.body.password !== "000000") {
return res.send({
status: 1,
msg: "登录失败",
});
}
req.session.user = req.body;
req.session.islogin = true;
res.send({
status: 0,
msg: "登录成功",
});
});
app.get("/api/username", (req, res) => {
if (!req.session.islogin) {
return res.send({ status: 1, msg: "fail" });
}
res.send({ status: 0, msg: "success", username: req.session.username });
});