Node.js
起步
加载模块
// 使用核心模块之前,首先加载核心模块
let path = require('path');path
路径操作
baename
返回文件名 如:index.js
let path = require('path');
let n = 'C:/Users/code/index.js';
console.log(path.basename(n)) //index.js如果想要返回的文件名不加后缀,可以这么做
let path = require('path');
let n = 'C:/Users/code/index.js';
console.log(path.basename(n,'.js')) //indexdirname
返回目录名 如:C:/Users/code
let path = require('path');
let n = 'C:/Users/code/index.js';
console.log(path.dirname(n)) //C:/Users/codeextname
返回文件后缀 如:.js
let path = require('path');
let n = 'C:/Users/code/index.js';
console.log(path.extname(n)) //.jsjoin
拼接路径 如:C:/Users/code/ + index.js = C:\Users\code\index.js
let path = require('path');
let n = 'C:/Users/code/';
let m = 'index.js'
console.log(path.join(n,m)) //C:\Users\code\index.jsformat
将对象转换为字符串路径
let path = require('path');
let n = path.format({
dir: 'C:\\Users\\code',
base: 'index.js'
});
console.log(n) //C:\Users\code\index.jsparse
将字符串路径转换为对象
let path = require('path');
let n = 'C:/Users/code/index.js';
console.log(path.parse(n))
// 返回结果如下:
/*
{
root: 'C:/',
dir: 'C:/Users/code',
base: 'index.js',
ext: '.js',
name: 'index'
}
*/__dirname
返回当前的文件的绝对路径
console.log(__dirname) //C:\Users\33111\Desktop\Demoresolve
合并路径
扩展
../
let path = require('path');
console.log(path.join('/foo', 'bar', 'quux'))正常拼接:\foo\bar\quux
. 跟 ./ 是返回当前路径
console.log(path.join('/foo', 'bar', 'quux','.'))
// \foo\bar\quux
console.log(path.join('/foo', 'bar', 'quux','./'))
// \foo\bar\quux\而 .. 跟 ../ 是返回上级路径
console.log(path.join('/foo', 'bar', 'quux','..'))
// \foo\bar
console.log(path.join('/foo', 'bar', 'quux','../'))
// \foo\bar\fs
文件操作
readFile
读取文件内容 如:读取 text.txt 的内容
**注意:**路径文件记得加单位
let fs = require('fs');
fs.readFile('./text.txt',(err,data)=>{
console.log(data)
// 输出结果:<Buffer e5 88 98 e5 ae 87 e9 98 b3>
})他的输出结果是: <Buffer e5 88 98 e5 ae 87 e9 98 b3> 二进制代码,并不是我们想要的结果。所以需要先 设置为utf-8模式 或者 转换为字符串
转换为正常文本
let fs = require('fs');
// 设置为utf-8模式
fs.readFile('./text.txt','utf-8',(err,data)=>{
console.log(data) //刘宇阳
})
// 或者用toString转换为字符串
fs.readFile('./text.txt',(err,data)=>{
console.log(data.toString()) //刘宇阳
})- 它的参数第一个参数
err是失败后执行 - 第二个参数
data是成功执行,参数名可以自定义
读取成功
let fs = require('fs');
fs.readFile('./text.txt','utf-8',(err,data) => {
if(err){
return console.log('读取失败!')
}
console.log('读取成功') //读取成功
console.log(data) //刘宇阳
})读取失败
let fs = require('fs');
// 把路径改错,使加读取失败
fs.readFile('./text.txt','utf-8',(err,data) => {
// 读取失败,err就有值 / 读取成功,err值就是null
// err有值就是true 没有值就是false
if(err){
return console.log('读取失败!') //读取失败
}
console.log('读取成功')
console.log(data)
})writeFile
写入文件内容 如:修改 text.txt 的内容
let fs = require('fs');
fs.writeFile('./text.txt','Hello World!', () => {})readdir
获取指定目录下的文件名称
const fs = require("fs");
fs.readdir(__dirname + "/docs", (err, res) => {
console.log(res);
// [ '1.md', '2.md', '3.md' ]
});同步方式
const res = fs.readdirSync(__dirname + "/docs")extname
获取指定文件的后缀
const path = require("path");
console.log(path.extname("index.html")); //.html
console.log(path.extname("index.css")); //.css
console.log(path.extname("index.js")); //.js当前文件夹下指定后缀的文件
const fs = require("fs");
const path = require("path");
fs.readdir(__dirname + "/docs", (err, data) => {
const res = data.filter((item) => path.extname(item) === ".md");
console.log(res);
// [ '1.md', '2.md', '3.md' ]
});整理成绩案例
将 text.txt 文件中的:小明=100 小王=98 小亮=97 小红=97 每个 等于号 (=) 换成 冒号 (:) 并且换行显示。
如下效果:
小明:100
小王:98
小亮:97
小红:97
代码实现
const fs = require('fs');
// 读取文件数据
fs.readFile('./text.txt','utf-8',function(err,data){
if(err) return console.log(err);
// 用于合并数据
let str = '';
// 将数据以空格转换为字符串
let arr = data.split(' ');
// 循环格式
arr.forEach(item=>{
str += item.split('=').join(':')+'\n'
})
// 写入文件数据
fs.writeFile('./text.txt',str,function (){})
})创建Web服务
// 加载http模块
let http = require('http');
// 创建Web服务对象
let server = http.createServer();
// 注册request事件
server.on('request',function(req,res){
console.log('收到客户端请求')
res.end('Hello') //响应数据
})
// 绑定端口号,启动服务
server.listen(8080,function(){
console.log('服务器启动成功了,可以通过 http://127.0.0.1:8080/ 来进行访问');
})注意:res.end(这里只能写字符串哦!) 如果数组或对象,可以使用 JSON.stringify 转换为字符串
req
req.url 获取请求的 URL 地址
req.method 获取是以什么方式请求的接口
例如使用POST请求:http://127.0.0.1:80/index.html
serve.on("request", (req, res) => {
console.log(req.url); //index.html
console.log(req.method); //POST
res.end("你好:Nodejs");
});res
向服务器发送请求
解决页面中文乱码问题
服务器接口 res.end 返回给页面中的数据默认会乱码,以下可以解决中文乱码问题
const http = require("http");
const serve = http.createServer();
serve.on("request", (req, res) => {
// 调用 res.setHeader() 方法,设置Content-Type 响应头 解决中文乱码问题
res.setHeader("Content-Type", "text/html; charset=utf-8");
res.end("你好:Nodejs");
});
serve.listen(80, () => {
console.log("服务器已启动:http://127.0.0.1:80");
});练习
根据不同请求页面显示不同内容
serve.on("request", (req, res) => {
const url = req.url;
console.log(url);
// 调用 res.setHeader() 方法,设置Content-Type 响应头 解决中文乱码问题
res.setHeader("Content-Type", "text/html; charset=utf-8");
// 找不到就显示404页面
let content = "<h1>404页面</h1>";
if (url === "/" || url === "/index.html") {
content = "<h1>首页</h1>";
} else if (url === "/cate.html") {
content = "<h1>分类页面</h1>";
}
res.end(content);
});将项目运行到服务器并且默认打开index.html文件
serve.on("request", (req, res) => {
const url = req.url;
let fpath = '';
// 如果请求的路径是 / 则手动指定文件的存放路径
if(url === '/'){
fpath = path.join(__dirname,'./view/index.html');
}else{
// 如果请求的路径不为 / 则动态拼接文件的存放路径
fpath = path.join(__dirname,'./view',url);
}
console.log(fpath);
// 请求哪个页面,就显示对应页面的内容
fs.readFile(fpath,(err,data)=>{
if(err) return res.end('<h1>404页面</h1>')
res.end(data)
})
});模块化
模块化有两种规范,分别是:ES6 与 commonJS,而默认情况下是:commonJS
ES6模块化规范
如果需要使用ES6模块化需要打开 package.json 添加一行代码:"type": "module" 即可使用 ES6 模块化规范
导出
// 默认导出
export default {
name:'刘宇阳',
fun:function(){}
}
// 按需导出
export let age = 19;导入
import obj from './txt.js'; //默认导出不需要加花括号
import {age} from './txt.js'; //按需导出需要加花括号
console.log('我叫:' + obj.name + ' 今年:' + age + '岁') //我叫:刘宇阳 今年:19岁ES6规范模块化的路径文件必须要加后缀 .js 比如:'./txt.js'
commonJS 可加可不加
CommonJS
按需导出
module.exports.name = "刘宇阳"默认导出
module.exports = {
name:"刘宇阳"
}exports
由于 module.exports 写起来比较复杂,为了简化向外共享成员的代码,Node提供了 exports 对象。默认情况下 exports 和 module.exports 指向的同一个对象。最终共享的结果还是以 module.exports 指向的对象为准。
console.log(module.exports === exports); //true导入
const obj = require('./module');
console.log(obj);注意:
- 导入内置或者第三方模块不需要加路径,而导入自定义模块需要加上路径
- 导入的自定义模块文件可以加后缀也可以不加,默认就是
module.js
npm
package.json 记录当前项目所依赖模块的版本信息,更新模块时锁定模块的大版本号(版本号的第一位)。
package-lock.json 记录了node_modules目录下所有模块的具体来源和版本号以及其他的信息。
初始化
安装本地模块,需要使用 npm 工具初始化。
npm init 或 npm init -y
初始化之后,会在项目目录中生成 package.json 的文件。
安装与卸载
安装
# 正常的下载安装
npm install 模块名
# 简写install为i
npm i 模块名
# 一次性安装多个模块
npm i 模块名 模块名 模块名卸载
npm uninstall 模块名
npm un 模块名
npm un 模块名 模块名 模块名更新
假如说你安装了某个包,当前版本是 2.0。过了几天包更新到了 3.0,如果你想要更新,不需要删除旧的包,直接:npm i 包名 即可覆盖之前旧的包,保留最新的。
切换镜像源
由于 npm 默认镜像是国外的,在安装 npm 包时候会下载很慢,所以我们需要切换到国内的 淘宝镜像源 ,淘宝镜像将 npm 包全部拷贝了一份,所以我们可以通过淘宝镜像来下载 npm 包,这样速度上会有明显提高
查看镜像源
npm config get registry切换到淘宝镜像源
npm config set registry=https://registry.npm.taobao.org
https://registry.npm.taobao.org/nrm
为了更方便的切换镜像源,我们可以安装 nrm 这个小工具,利用 nrm 提供的终端命令,可以快速的查看和切换镜像源
安装
npm i nrm -g查看可用的镜像源
nrm ls将镜像源切换为 淘宝 镜像
nrm use taobaoExpress
创建一个基本Web服务器
// 导入express
const express = require('express')
// 创建Web服务器
const app = express()
// 调用app.listen(端口号,启动成功后的回调函数),启动服务器
app.listen(80,()=>{
console.log('express serve running at http://127.0.0.1/');
})发起请求
// 导入express
const express = require("express");
// 创建Web服务器
const app = express();
// 监听客户端的 GET 和 POST请求,并向客户端响应具体的内容
app.get("/user", (req, res) => {
// 响应一个对象
res.send({ name: "刘宇阳", age: 20, sex: "男" });
});
// post请求
app.post("/user", (req, res) => {
// 响应一个字符串
res.send("Hello");
});
// 调用app.listen(端口号,启动成功后的回调函数),启动服务器
app.listen(80, () => {
console.log("express serve running at http://127.0.0.1/");
});处理参数
req.query
GET请求接口:http://127.0.0.1/user?name=刘宇阳&age=20
app.get("/user", (req, res) => {
console.log(req.query); //{ name: '刘宇阳', age: '20' }
});req.params
GET请求接口:http://127.0.0.1/user/1/刘宇阳
app.get("/user/:id/:name", (req, res) => {
console.log(req.params); //{ id: '1', name: '刘宇阳' }
});托管静态资源
express 提供了非常好用的函数:express.static() 通过它我们可以非常方便的创建一个静态资源服务器,例如通过如下代码就可以将 public 目录下的 图片、HTML、CSS、JavaScript 文件对外开放访问了
app.use(express.static('public'))express 在指定的静态目录中查找文件,并对外提供资源的访问路径,因此存放静态文件的目录名不会出现在 URL 中。
如果想要托管多个静态资源目录,请多次调用 exports.static() 函数
app.use(express.static('public'))
app.use(express.static('view'))访问静态资源文件时,exports.static() 函数会根据目录的添加顺序查找所需的文件
例如:public 与 view 都有 index.html 文件,如果访问了 index.html 就会触发 public 中的index.html,因为他在前,view 在后
挂载路径前缀
如果希望在托管的静态资源访问路径之前挂载路径前缀,这可以使用如下方式:
app.use('/public',express.static('public'))这样你可以通过带有 /public 前缀地址来访问 public 目录中的文件了
中间件
内置中间件
快速托管静态资源的内置中间件
app.use(express.static())配置解析 application/json 格式数据
app.use(express.json())配置解析 application/x-www-form-urlencoded 格式数据
app.use(express.urlencoded({extended:false}))错误处理中间件
如果不使用错误中间件,项目中某个地方发生错误,就会导致整个项目崩溃。所以就需要用到错误处理的中间件
// 定义路由
app.get("/", (req, res) => {
throw new Error("服务器内部发生了错误!");
res.send("这里不会被触发");
});
// 定义错误中间件,捕获整个项目的异常错误,从而防止程序的崩溃
app.use((err, req, res, next) => {
console.log("发生了错误:" + err.message);
res.send("Error:" + err.message);
});跨域
- 安装
cors
npm install cors
# or
yarn add cors- 导入
cors
const cors = require('cors');- 安装
cors到中间件
app.use(cors());JWT
安装JWT相关包
yarn add jsonwebtoken express-jwtjsonwebtoken:用于生成 JWT 字符串
express-jwt:用于将 JWT 字符串解析还原成 JSON 对象
生成Token
使用 JWT 生成 Token 当登录成功后返回给客户端
var express = require("express");
var router = express.Router();
const jwt = require("jsonwebtoken");
// token秘钥
const secretKey = "LiuYuYang ^_^";
router.post("/login", function (req, res, next) {
const { username, password } = req.body;
if (username != "admin" || password != "123123") {
return res.send({ status: 0, msg: "登录失败!" });
} else {
// 生成Token
// const token = jwt.sign({需要加密的信息}, 秘钥(secretKey), { expiresIn: "到期时间" });
const token = jwt.sign({ username }, secretKey, { expiresIn: "30s" });
res.send({
status: 1,
msg: "登录成功!",
user: req.body,
token
});
}
});
module.exports = router;校验Token
导入 express-jwt
const { expressjwt } = require("express-jwt");设置到中间件
app.use(
expressjwt({ secret: secretKey, algorithms: ["HS256"] }).unless({
path: [/^\/login],
})
);只有 /login 接口有权限访问,其他接口无权访问,除非在请求头 Headers 中的 Authorization 加上 Token 字符串发送到服务器进行身份认证
操作数据库
操作SQL
例子:查询数据表中所有数据
const mysql = require("mysql");
const pool = mysql.createPool({
connectionLimit: 150,
host: "localhost",
user: "root",
password: "123123",
database: "data",
});
pool.getConnection(function (err, db) {
if (err) return;
// 所有sql语句写在query的第一个参数
db.query("select * from stu", function (err, data) {
if (err) throw error;
console.log(data);
db.release();
});
});新增数据
pool.getConnection(function (err, db) {
if (err) return;
db.query("insert into stu values(0, '尤雨溪', 30, 175.6, '男')", function (err, data) {
if (err) throw error;
console.log(data);
db.release();
});
});快捷操作
pool.getConnection(function (err, db) {
if (err) return;
let obj = { name: "尤雨溪", age: 30, height: 175.6, gender: "男" };
// insert into stu values(0, '尤雨溪', 30, 175.6, '男');
db.query("insert into stu set ?", obj, function (err, data) {
if (err) throw error;
console.log(data);
db.release();
});
});pool.getConnection(function (err, db) {
if (err) return;
// insert into stu values(0, '尤雨溪', 30, 175.6, '男');
db.query("insert into stu values(?, ?, ?, ?, ?)", [0, '尤雨溪', 30, 175.6, '男'], function (err, data) {
if (err) throw error;
console.log(data);
db.release();
});
});更新数据
pool.getConnection(function (err, db) {
if (err) return;
db.query("update stu set name='比尔盖茨',age=20,height=185,gender='男' where id = 2", function (err, data) {
if (err) throw error;
console.log(data);
db.release();
});
});快捷操作
pool.getConnection(function (err, db) {
if (err) return;
// update stu set name='比尔盖茨', age=20, height=185, gender='男' where id = 2;
db.query("update stu set name=?, age=?, height=?, gender=? where id=?", ['比尔盖茨', 30, 165.50, '男', 2], function (err, data) {
if (err) throw error;
console.log(data);
db.release();
});
});pool.getConnection(function (err, db) {
if (err) return;
let obj = {id:3, name: "尤雨溪", age: 30, height: 175.6, gender: "男" };
// update stu set name='比尔盖茨', age=20, height=185, gender='男' where id = 2;
db.query("update stu set ? where id = ?", [obj, obj.id], function (err, data) {
if (err) throw error;
console.log(data);
db.release();
});
});删除数据
pool.getConnection(function (err, db) {
if (err) return;
db.query("delete from stu where id = 5", function (err, data) {
if (err) throw error;
console.log(data);
db.release();
});
});快捷操作
pool.getConnection(function (err, db) {
if (err) return;
// delete from stu where id = 5;
db.query("delete from stu where id = ?", 5, function (err, data) {
if (err) throw error;
console.log(data);
db.release();
});
});标记删除
- 使用
Delete语句会把真正的数据从表中删除掉,为了保险起见,推荐使用标记删除的形式来模拟删除操作。 - 所谓标记删除就是在表中设置类似于
status这样的状态字段来标记当前这条数据是否被删除。 - 当用户执行了删除的动作时,我们并没有执行
Delete语句把数据删除掉,而是执行了Update语句将这条数据对应的status字段标记为已删除即可
字段值可以用:1 代表已删除 0 代表未删除
pool.getConnection(function (err, db) {
if (err) return;
// 将id为6的那条数据status字段设置为1,代表已删除
db.query("update stu set status = 1 where id = ?", 6, function (err, data) {
if (err) throw error;
console.log(data);
db.release();
});
});封装数据库操作SQL
// 导入MySQL
const mysql = require('mysql');
// 创建数据库连接对象
const pool = mysql.createPool({
connectionLimit: 150,
host: 'localhost', //主机地址
user: 'root', //用户名
password: '123123', //密码
database: 'data' //数据库名称
});
function query(sql) {
return new Promise(function (resolve, reject) {
// 连接数据库
pool.getConnection(function (err, db) {
if (err) return;
// 执行SQL语句
db.query(sql, function (err, data) {
if (err) throw error;
resolve(data);
// 释放数据库
db.release()
});
})
})
}
// 导出
module.exports = query