1.MongDB的使用
????如果你玩过微信小程序的云开发或者学过MySQL,这玩意儿相对要好学很多。作为非关系型数据库,MongDB由 C++ 语言编写。旨在为 WEB 应用提供可扩展的高性能数据存储解决方案。MongDB其实使用面还是比较广的,每条记录有点像json数据,一般和node.js在一起作为后端架构,在Java中也有一定的使用空间(主要用于存储可丢失的数据)。好,简单介绍完毕,接下来就是基本的使用介绍了。
1.1MongDB的安装
????首先自然是(从官网下载)了,应该需要注册啥的,这里用的是社区版,企业版应该会收费,学习的话用社区版应该足够了。下载时,选择custom,修改文件路径到E盘,节省C盘空间。下载完成之后配置环境变量(eg.E:\MongoDB\bin )。配置完成之后:
1.2数据库的基本操作指令
show dbs
use 数据库名称
db/db.getName()
db.stats()
db.version()
db.getMongo()
db.dropDatabase()
1.3数据集合(表)的基本操作指令
db.createCollection("collName",{size:20,capped:true,max:100})
db.getCollectionNames()
db.printCollectionStats()
db.collection名称.drop()
1.4文档(记录)的基本操作指令
db.test.insert({name:"张三",age:22})
db.test.update({name:"张三",age:22},{$set:{age:19}});
db.test.update({name:"张三",age:22},{$inc:{age:100}});
db.test.remove({data:1},false)
db.test.find()
db.test.distinct('name')
db.test.find({data:1})
db.test.find({data:{$gt:1}})
db.test.find({data:{$gte:1}})
db.test.find({data:{$lt:1}})
db.test.find({data:{$gt:1,$lt:5}})
db.test.find({name:/nightowl/})
db.test.find({name:/^nightowl/})
db.test.find({name:/nightowl$/})
db.test.find({},{name:0,_id:0})
db.test.find().sort(data:1)
db.test.find().sort(data:-1)
db.test.find().limit(5)
db.test.find().skip(3)
db.test.find({$or:[data:{$gt:1},data:{$lte:-3}]})
db.test.findOne()
db.test.find({条件}).count()
2.JWT的使用
????首先,简单说一下JWT(Json Web Token),主要应用场景是前后端鉴权。为了保护数据库里面的数据,避免非法用户攻击,前端首次登录之后,后端会利用某种加密算法,将用户名(或者其他能够唯一标识用户的信息,当然为了提高安全性,也可能涉及其他信息)生成一个token(这里的token是一般使用的代号,其他名字也可以),将token发送给前端,然后前端在请求数据的时候需要携带token信息,后端会再次加密这些信息,将两次token进行验证,验证通过才进一步调用model层获取数据库里面的数据或者向数据库里面写入数据。 ????当然更深入的,后端还可以利用像redis一样的高速缓存工具,快速验证前端传过来的token。其基本是实现原理是前端第一次登录,将生成的token存入redis,之后用户再次请求,直接查找redis是否含有先前生成好的token,有便通过验证。下面主要介绍利用JWT实现的对称加密和非对称加密。 ????首先是对称加密,为了方便更加熟悉RMVC模式(router、model、view、controller),我们回顾一下前面搭建目录的过程:
const express = require("express");
const app = express();
const router = require("./route/index");
app.use("/", router);
app.listen(3000, () => {
console.log("localhost:3000.");
});
const express = require("express");
const router = express.Router();
const loadToken = require("../controller/token");
router.get("/api/token", loadToken);
module.exports = router;
const jwt = require("jsonwebtoken");
const token = (req, res, next) => {
const loadToken = jwt.sign({ username: "张三、李四、王五牛逼!**nightowl**" },
"nightowl"
);
res.send(loadToken);
};
module.exports = token;
????补充说明,这里需要导入的模块有:express、express-generator(前两者主要是为了引入express极简框架)、jsonwebtoken(引入JWT加密模块)、nodemon(项目热加载,省得每次修改代码之后需要重启)。这里使用的是对称加密,jwt.sgin() 方法含有两个参数,第一个参数是被加密的数据,第二个参数是加密的私钥(补充:所谓的对称加密指的是加密和解密用的私钥和密钥是一样的 )。这里介绍一个(JWT官网),可以用来解密JWT生成的数据。解密效果如下: ????其中的蓝色部分是私钥,又被成为数字签证,可以通过右边的输入框来更改。当然jwt自身提供了解密方法jwt.verify() ,这种对称加密其实不算安全,因为如果别人知道了密钥,信息就很容易泄露,加上公钥与私钥一直,增大了泄露的风险。 ????接下来说一下非对称加密。非对称加密有点类似于git的环境搭建,首先需要生成私钥和公钥,然后将公钥上传到自己的git远程仓库上。在jsonwebtoken中,非对称加密的实现方法为: (1)(下载openSSL)(用来生成签证); (2)在cmd中执行 genrsa -out rsa_private_key.pem 2048 ,生成2048位私钥; (3)执行rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem 生成公钥; 生成完成之后的文件如下所示: ????之后修改对应的加密算法:
const jwt = require("jsonwebtoken");
const fs = require("fs");
const path = require("path");
const token = (req, res, next) => {
const privateKey = fs.readFileSync(
path.join(__dirname, "../rsa_private_key.pem")
);
const publicKey = fs.readFileSync(
path.join(__dirname, "../rsa_public_key.pem")
);
const loadToken = jwt.sign({ username: "张三" }, privateKey, {
algorithm: "RS256",
});
const result = jwt.verify(loadToken, publicKey);
console.log("输出解密之后的数据:", result);
res.send(loadToken);
};
module.exports = token;
????程序运行结果如下: ????里面展示的时间iat其实就是时间戳,对应当前密文生成的时间。在策略上,可以将公钥发送给后端,当前端上前数据时先用私钥加密,等数据到达后端之后,利用后端传入的公钥解密数据或者两次加密数据看数据是否相等。
3.socket编程
3.1原生socket编程
????socket编程更偏向于计算机网络数据传输方面的底层知识,这里可以作为了解内容,因为现在框架对于socket的封装程度已经比较高了。数据传输分为双工通信、单工通信和半双工通信,其中单工通信就类似于数码电视,只接受另外一段传输过来的数据,双工通信就类似于QQ,信息的接受和发送能够同时进行,半双工通信类似于老式手机“大哥大”,需要一段给出回应才能够继续发送。接下来简单说说如果撤掉各种框架的封装,使用最底层的socket如何实现数据通信: socket属于node.js中内置模块Net模块,程序举例如下:
const net = require("net");
const server = net.createServer((socket) => {
socket.write("hello client!");
socket.on("data", (chunk) => {
console.log("来自客户端的数据:", chunk.toString());
});
});
server.on("error", (err) => {
console.log("服务端错误", err);
});
server.listen("8080", () => {
console.log("opened server on:", server.address());
});
const net = require("net");
const client = net.createConnection({ port: 8080 }, () => {
console.log("connect to server!");
client.write("hello server!");
});
client.on("data", (chunk) => {
console.log("来自服务端的数据:", chunk.toString());
});
client.on("error", (err) => {
console.log("客户端错误", err);
});
????程序执行效果如下: 对于聊天室的模拟,程序实现如下:
const net = require("net");
const server = new net.createServer();
let clients = {};
let clientName = 0;
server.on("connection", (client) => {
client.name = ++clientName;
console.log("客户端NO", client.name, "获得与server的连接!");
clients[client.name] = client;
client.on("data", (msg) => {
broadcast(client, msg.toString());
});
client.on("close", () => {
delete clients[client.name];
console.log("客户端NO" + client.name, "与server断开连接!");
});
});
function broadcast(client, msg) {
for (var key in clients) {
if(key!=client.name){
clients[key].write("客户端NO" + client.name + "说:" + msg);
}
}
}
server.listen(8080, () => {
console.log("server 开启!");
});
const net = require("net");
const readline = require("readline");
let socket = new net.Socket();
const port = 8080;
const host = "127.0.0.1";
socket.setEncoding = "UTF-8";
socket.connect(port, host, () => {
socket.write("hello.");
});
socket.on("data", (msg) => {
console.log(msg.toString());
say();
});
const r1 = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
function say() {
r1.question("请输入向server传输的数据:\n", (inputMsg) => {
if (inputMsg != "bye") {
socket.write(inputMsg + "\n");
} else {
socket.destroy();
r1.close();
}
});
}
socket.on("error", (err) => {
console.log("client error", err);
socket.end();
});
????难点,数据之间的传输,一个传输对应一个监听处理,坑点:wirte() 函数不能直接传输对象,因此不能使用, 来凭借多个字符串。 实现效果如下:
3.2WebSocket第三方依赖
????除了接近底层外,socket中我们能够发现一个特点,server端可以直接向服务端发送数据,也就可以解决消息推送等问题,实现真正意义的双工通信,http是不能够做到这一点的,http协议下只能由client请求。讲道理我之前还没深入到WebSocket,可以看看(阮老师的博文),看到WebSocket之后才发现自己前端也就学了点皮毛,WebSocket的协议标识为ws ,加密之后用的是wss ,无同源策略。现在还学的比较少,应该用不上这么多,但是需要知道有这个东西。需要注意的是web浏览器中由WebSocket,在node.js中如果需要用到WebSocket,需要使用第三方依赖,安装方式:npm install ws -S ,程序代码如下: ????服务端代码:
const webSocket = require("ws");
const ws = new webSocket.Server({ port: 8080 });
let clients = {};
let num = 0;
function broadcast(client, msg) {
for (let key in clients) {
clients[key].send("来自客户端NO" + client.name + "的数据:" + msg);
}
}
ws.on("connection", (client) => {
client.name = ++num;
clients[client.name] = client;
client.on("open", () => {
ws.send("来自客户端的hello");
});
client.on("message", (msg) => {
console.log("来自客户端NO" + client.name + "的数据:", msg.toString());
broadcast(client, msg);
});
client.on("close", () => {
console.log("客户端NO" + client.name + "已断开连接~");
delete clients[client.name];
});
});
ws.on("close", () => {
console.log("服务端已经关闭!");
});
????客户端代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>websocket</title>
<script src="./client.js"></script>
</head>
<body>
<div>我是一个websocket测试客户端</div>
</body>
</html>
const ws = new WebSocket("ws://localhost:8080");
ws.onopen = () => {
console.log("client open");
ws.send("你好呀,服务端");
};
ws.onmessage = (socket) => {
console.log("来自服务端的数据:", socket.data);
};
ws.onerror = () => {
console.log("客户端错误");
};
ws.onclose = () => {
console.log("客户端关闭连接");
};
????其实这个代码比较简单,很好理解,需要注意server.js 里面的client 不能理解成客户端,应该理解成服务端那边用来管理与客户端会话的管理者 。这个只是一个框子,我自己也没有实践过由server端主动向client端发信息,后续还得通过实际项目进一步练习。
3.3socket.io的使用
????有些浏览器不支持H5,这使得有些时候WebSocket的应用收到了一定的限制,WebSocket可以理解成socket在浏览器端应用场景下的一种优化封装,而socket.io就是对socket更加系统的优化,WebSocket,可以算作是socket.io的一个子集。如果使用socket.io的话,程序代码如下: 服务端:
var express = require("express");
var app = express();
var server = require("http").Server(app);
var io = require("socket.io")(server, { cors: true });
io.on("connection", function(socket) {
console.log("有客户端与服务端建立连接");
socket.on("receive", (msg) => {
console.log("输出服务端收到的数据:", msg);
socket.emit("message", "收到 over !");
});
});
server.listen(8080, () => {
console.log("localhost:8080");
});
客户端:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>socket.io</title>
<script src="./node_modules/socket.io/client-dist/socket.io.js" charset="utf-8"></script>
</head>
<body>
<div>
<input type="text" id="msg" style="width: 200px;">
</div>
<button id="submit">点击发送表单消息</button>
<script>
var socket = io.connect('http://127.0.0.1:8080');
const content = document.getElementById('content')
document.querySelector('#submit')
.addEventListener('click', () => {
let content = document.getElementById("msg").value;
socket.emit('receive', content);
})
socket.on('message', (msg) => {
console.log("输出客户端收到的数据:", msg);
})
</script>
</body>
</html>
需要注意的是,消息的传递都需要绑定一个信息传输标识,比如上面的"message"和"receive",如果遇到了跨域问题,直接在创建server的时候允许跨域。相比于WebSocket在写法上更加简单了
|