1. 静态资源目录
静态资源目录就是访问服务器的某些路劲时候,服务器可以吐出一个写好的指定页面。
实现思路:
1、先判断要找的路径是否是文件,如果是文件,就加载发给对方。
2、如果是文件夹,找到这个文件夹所在路径中有没有index.html,如果有加载发送。
3、如果文件夹,并没有index.html,加载404发送。
案例:
1. 创建一个api的文件夹,打开集成终端执行npm init -y 命令得到一个package.json文件,编写该文件。
{
"name": "api",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "nodemon PORT=4000"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"nodemon": "^3.1.4"
},
"dependencies": {
"cheerio": "^1.0.0",
"jsonwebtoken": "^9.0.2",
"mime": "^3.0.0",
"node-xlsx": "^0.24.0"
}
}
2. 创建入口文件index.js ,
3.创建staticPublic.js文件,编写该文件。在集成终端中执行npm start 命令启动命令。
const http = require("http");
const path = require("path");
const mime = require("mime");
// 创建一个服务
http.createServer(async function (req, res) {
// 获取到响应对象的路劲
let url = req.url;
// 加载
let [result, mimeType] = await getFile(url)
//编写请求头
res.writeHead(200, {
// 如果是文本文件就解析它,如果不是文本文件就直接返回
"Content-Type": /text/.test(mimeType) ? mimeType + ";charset=utf-8" : mimeType
})
res.end(result);
}).listen(process.env.PORT)
// 获取文件函数
async function getFile(url) {
// 获取当前文件的上一级路劲并拼接上public
const paths = path.join(path.resolve(), "public", url);
// 使用fsp.stat()方法获取到路劲最后面的路劲判断是不是文件
const stat = await fsp.stat(paths).catch(e => { });
// 不是文件的情况,则返回404页面
if (!stat) {
return await getFile("/404.html");
}
// 是文件的情况
if (stat.isFile()) {
// 使用mime.getType()方法判断文件类型
return [await fsp.readFile(paths), mime.getType(paths)];
// 是文件夹的情况
} else if (stat.isDirectory()) {
// 获取到当前文件的上一级路劲并拼接上index.html页面
return await getFile(path.join(url, "./index.html"))
}
}
4.在入口文件index.js 中导入staticPublic.js文件。
require("./staticPublic")
5. 创建一个public的文件夹,在创建一个image文件夹存放几张图片。
6. 在public的文件夹下创建一个index.html文件和一个404.html文件,并编写该文件。
index.html文件:
<body>
<a href="#">超链接</a>
<img src="/img/img_12.JPG">
</body>
404.html文件:
<body>
<h1>404</h1>
</body>
2. 爬虫
爬虫:获取一个网页中全部的文件和内容。一般用于静态页面。
爬虫使用的插件:cheerio是模仿jQuery方式实现的一个第三方爬虫解析插件,可以将文本像html一样通过选择器和筛选器将数据分离。
方法:
cheerio.load(数据结果) :加载数据。
$("标签名/类名/id名").each((index, item) => { ...} : 遍历。
$(标签名).attr("属性名"); :获取标签的某个属性。
1. 在api的文件夹下创建一个reptile.js文件,并编写该文件。
// 引入https模块
const https = require("https");
// 引入爬虫插件
const cheerio = require("cheerio");
// querystring解析模块
const querystring = require("querystring");
// 引入文件模块
const fsp = require("fs/promises")
const path = require("path");
// 获取到网址
https.get("https://news.163.com/", async function (respone) {
let list = [];
// 调用该函数获取到网址上的数据
let result = await getData(respone)
// 使用cheerio.load()解析数据
let $ = cheerio.load(result)
// 使用元素选择器获取到所有的img标签,然后遍历
// index:元素索引, item:元素
$("img").each((index, item) => {
// 获取到img标签的src属性
let src = $(item).attr("src");
// 没有src属性的情况
if (!src) {
// 使用querystring.parse()解析获取到data-original属性
src = querystring.parse($(item).attr("data-original").split("?")[1]).url;
}
list.push(src);
})
for (var i = 0; i < list.length; i++) {
// 如果没有https开头就要添加一个https
if (!/https?/.test(list[i])) list[i] = "https:" + list[i];
let result = await getFile(list[i]);
if (!result) continue;
let fileName = list[i].split("/").pop();
await fsp.writeFile(path.join(path.resolve(), "./public/img", fileName), result)
}
})
// 获取数据的函数
function getData(req) {
return new Promise(function (resolve, reject) {
let data = ""
req.on("data", _chunk => data += _chunk);
req.on("end", () => resolve(data))
})
}
// 获取文件数据都函数
function getFile(url) {
return new Promise(function (resolve, reject) {
https.get(url, async function (respone) {
let result = await getImageData(respone);
resolve(result);
})
})
}
// 获取图片数据的函数
function getImageData(req) {
return new Promise(function (resolve, reject) {
let data = Buffer.alloc(0);
req.on("data", _chunk => {
data = Buffer.concat([data, _chunk], data.length + _chunk.length);
});
req.on("end", () => resolve(data))
})
}
2.在入口文件index.js 中导入reptile.js文件。
require("./reptile");
3. Excel表格解析
Excel表格解析需要先下一个第三方模块node-xlsx,这里完成了一个excel表格筛选重建的内容然后创建一个新的表格文件。
1. 在api的文件夹下创建一个excels.js文件,并编写该文件。
const fsp = require("fs/promises");
const xlsx = require("node-xlsx");
const path = require("path");
init();
async function init() {
// 读取文件内容
let result = await fsp.readFile(path.join(path.resolve(), "./public/excel/cjd.xlsx"))
// 使用xlsx.parse()解析数据,获得一个数组对象
let data = xlsx.parse(result);
// 把总分不及格的人筛选出来
let data1 = data[0].data.filter((item, index) => {
// 不是元素第4项直接跳出
if (index < 4) return true;
return Number(item[item.length - 1]) < 60;
})
// 创建一张excels表格
let buffer = xlsx.build([{ name: "不及格的成绩单", data: data1 }]);
// 把筛选出来数据写入表格
await fsp.writeFile(path.join(path.resolve(), "./public/excel/a.xlsx"), buffer)
}
2. 在入口文件index.js 中导入excels.js文件。
require("./excels");
4. Crypto原生加密
引入语法:const crypto = require("crypto");
方法:
crypto.createHmac(加密key, 要加密的字符串) .update("更新的密码").digest("指定字符集")
const crypto = require("crypto");
var str = 'abcdef';
var hash = crypto.createHmac("sha256", str).update("123456").digest("dex")
console.log(hash);
5. bcrypt 第三方加密
下载命令:npm i bcrypt -S
加密:
bcrypt.hash(password,10,function(err,encryted){
console.log(encryted);
})
验证:
bcrypt.compare(pass,hash,function(err,bool){
console.log(bool);
})
6. jsonwebtoken加密
下载命令:npm i jsonwebtoken
引入语法:const jsonwebtoken = require("jsonwebtoken");
方法:
jsonwebtoken.sign(要加密的字符串, 加密key):加密
jsonwebtoken.verify(要解密密的字符串, 加密key):解密
对称加密 :加密的秘钥和解密的秘钥是完全相同的。
非对称加密 :加密的秘钥和解密的秘钥是不相同的。jsonwebtoken使用借助于openssl密钥的生成。私钥加密,公钥解密。
openssl下载地址:Win32/Win64 OpenSSL Installer for Windows - Shining Light Productions
打开openssl命令行:openssl
生成一个2048位的私钥:genrsa -out rsa_private_key.pem 2048
根私钥生成公钥:rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem
加密:
const jsonwebtoken = require("jsonwebtoken");
let key = "xietian";
let str = "abcdef";
let hash = jsonwebtoken.sign(str, key);
console.log(hash);
解密:
const jsonwebtoken = require("jsonwebtoken");
let key = "xietian";
let hash1 = "eyJhbGciOiJIUzI1NiJ9.YWJjZGVm.pazQAwUB0OAO-xlF6D0sV1r-lQCPGQcGwvUWV20fiuE";
let str1 = jsonwebtoken.verify(hash1, key);
console.log(str1);
案例1:
const jsonwebtoken = require("jsonwebtoken");
// 加密
var data = { name: "kwj", age: 20 };
let hash = jsonwebtoken.sign(data, "123456");
console.log(hash);
console.log("--------------------------");
// 解密
var data1 = { name: "xietian", age: 20 };
let hash1 = jsonwebtoken.verify(hash, "123456")
console.log(hash1);
案例2:jsonwebtoken的对称解密
// 对称加密 秘钥 加密的秘钥和解密的秘钥是完全相同的
// 可以多次加密解密
const jsonwebtoken = require("jsonwebtoken");
// 加密
var data = { a: 1, b: 2 };
var hash = jsonwebtoken.sign(data, "123456");
var hash1 = jsonwebtoken.sign(hash, "123456");
console.log(hash1);
console.log("----------------------------------");
// 解密
var hash2 = jsonwebtoken.verify(hash1, "123456");
var data1 = jsonwebtoken.verify(hash2, "123456");
console.log(data1);
案例3:jsonwebtoken的非对称解密
const jsonwebtoken = require("jsonwebtoken");
const fsp = require("fs/promises");
const path = require("path")
// 非对称加密
init();
async function init() {
var data = { name: "xietian", age: 20 };
var privateKey = await fsp.readFile(path.resolve("./rsa_private_key.pem"));
var hash = jsonwebtoken.sign(data, privateKey, { algorithm: "RS256" })
var publicKey = await fsp.readFile(path.resolve("./rsa_public_key.pem"));
var data1 = jsonwebtoken.verify(hash, publicKey);
console.log(data1);
}
7. cors跨域
下载命令:npm i cors -S
使用方法(固定写法) :app.use(cors())
8. 客户端版socket
连接分为长连接和短连接(客户端给服务端发消息,服务端返回消息,然后连接就断了)。
socket是一种长连接,因此需要保障每一个连接过来的客户端都被存储引用。
readline是读取终端的行消息。
引入模块:
const net = require('net');
服务端创建服务:
const server = new net.createServer();
客户端创建socket服务:
var socket = new net.Socket();
引入模块:
const readline = require("readline");
实现案例:
服务端:
1. 创建一个socketServer1文件夹,在该文件夹下打开集成终端执行npm init -y 命令初始化得到package.json文件,编写该文件。
{
"name": "socketserver1",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "nodemon PORT=4000 "
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"nodemon": "^3.1.4"
}
}
2. 在集成终端执行 npm i 和npm start命令。
3. 新建入口文件index.js,编写代码。
// 引入net模块
const net = require("net");
// 创建服务器(服务端)
const server = net.createServer();
// n表示连接成功的次数
let n = 0;
// 连接上的client集合
let list = {};
// server.on()方法是侦听connection事件的连接情况
server.on("connection", connnectionHandler);
// server.listen()开启端口号
server.listen(process.env.PORT);
// 侦听connection事件的函数(参数:客户端)
function connnectionHandler(client) {
n++;
// 相当于给进来的client取名字
client.name = n;
// client存入list
list[n] = client;
// console.log(Object.keys(list).length);
// 侦听客服端error出错事件的函数
client.on("error", () => errorHandler(client));
// 侦听客服端close关闭事件的函数
client.on("close", () => closeHandler(client));
// 侦听服务器发送数据给客户端的函数
client.on("data", (msg) => getMsgHandler(msg, client))
}
// 侦听客服端发送数据的函数
function getMsgHandler(msg, client) {
console.log(msg + "");
for (var key in list) {
list[key].write(msg + "");
}
}
// 侦听客服端error出错事件的函数
function errorHandler(client) {
console.log(client.name + " error");
// 关闭出错的client的连接
client.end();
}
// 侦听客服端close关闭事件的函数
function closeHandler(client) {
console.log(client.name + "关闭下线了");
// 关闭client的连接
client.end();
// 从集合中删除
delete list[client.name];
}
客服端:
1. 创建一个socketClient1文件夹,在该文件夹下打开集成终端执行npm init -y 命令初始化得到package.json文件,编写该文件。
{
"name": "socketclient1",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "node index.js"
},
"keywords": [],
"author": "",
"license": "ISC"
}
2. 新建入口文件index.js,编写代码。
// 也要引入net模块
const net = require("net");
// 读取终端行消息模块
const readline = require("readline");
// 这个代码让我们的命令行变为输入端和输出端
const order = readline.Interface({
// 这里是输入端
input: process.stdin,
// 这里是输出端
output: process.stdout
})
let socket;
init();
// 初始化函数
function init() {
// 客户端创建socket服务
socket = new net.Socket();
// 连接服务端(参数:4000的端口号,参数:域名或id地址,参数:连接成功的回调函数)
socket.connect(4000, "localhost", () => {
// 当连接上服务端执行这个函数
// 发信息的方法一:
// socket.write()方法是直接发消息给服务端
// socket.write("你好");
// 发信息的方法二:
// order.question("输入:", (msg) => {
// // 发送的消息
// })
})
// 侦听服务端发送回来的数据
socket.on("data", (msg) => msgHandler(msg));
inputShow();
}
function msgHandler(msg) {
console.log(msg + "");
}
// 使用readline模块的方法发送消息
function inputShow() {
order.question("输入:", (msg) => {
socket.write("谢天说:" + msg);
inputShow();
})
}
9.