NodeJS
模块化规范
- AMD - require.js
- CMD - sea.js
- CommonJS - NodeJS,利用 module.exports 或 exports 定义模块,利用 require() 引入依赖模块
- ES6 Modules
NodeJS 中,一个文件就是一个模块,在文件内部定义的变量,如果需要在其它文件中使用到,则需要通过 module.exports
导出,在其它要使用的文件中用 require()
引入即可。
nodemon
是一个监视文件夹中文件变化后自动重启 node 应用的工具。
$ npm i -g nodemon
package.json
项目配置文件
$ npm init -y
npm scripts
在 package.json 文件中,有一个 scripts
字段,可以在命令行中使用 npm run
来执行这个字段中的脚本:
{
"scripts": {
"start": "node ./bin/www",
"dev": "node ./bin/www",
"serve": "node ./bin/www"
},
}
可执行
$ npm run start # 对于 start 任务,可省略 run 的书写:npm start
$ npm run dev
$ npm run serve
npm
node package manager
- node 包资源管理器
安装包:
$ npm install <package-name@version> --save-dev
# 或
$ yarn add <package-name@version> --dev
# 或
$ cnpm install <package-name>
--save
是将安装包资源信息保存到 package.json 中的 dependencies 字段中,而--save-dev
是保存到devDependencies
中。--save
可以简写为-S
,--save-dev
可简写为-D
核心模块
- http-http模块
- fs-文件系统
- global-全局变量:
setTimeout/setInterval/require()/module/__dirname/__filename
- path - 路径
- querystring - 查询字符串
- events - 事件
- …
MongoDB - 数据库
安装
略
配置环境变量
复制安装目录下 bin
目录路径
我的电脑 --> 右键 --> 属性 --> 高级系统设置 --> 环境变量 --> 用户变量 --> path --> 编辑 --> 新建 --> 粘贴刚复制的 bin 目录路径 --> 确定关闭对话框
配置完毕后,重新打开新 cmd 提示符窗口,运行:
$ mongod --version
启动 MongoDB 服务
注意,windows 10 系统中,如果在服务中,MongoDB
服务的状态是正在运行,则不需要此操作
在命令行中执行:
$ mongod --dbpath <path-name>
<path-name>
是数据文件的保存路径,该路径需要事先先创建好。
启动服务后,命令窗口中的任务并没结束,请不要关闭(关闭窗口,则服务停止)
数据库概念
- database:数据库,容器,用于保存管理数据
- collection:集合(类似于 MySQL 中 table)
- document:文档(类似于 MySQL table 中的 row)
- primary key: 主键,唯一标识,默认
_id
为主键字段 - …
常用命令
- show dbs: 显示所有数据库
- db: 查看当前所在数据库,默认为
test
- use db-name: 切换数据库
- db.createCollection(coll-name): 创建集合(相当于表)
CRUD - CreateReadUpdateDelete
- db.coll-name.insert(): 向集合中插入文档
- db.coll-name.find(): 查找集合中的文档
- db.coll-name.update(): 修改集合中的文档
- db.coll-name.remove(): 删除集合中的文档
mongoose
用于在 NodeJS 应用中连接 MongoDB 数据库
安装
$ npm i mongoose
# 或
$ yarn add mongoose
使用
见案例
Express
基于 Node.js 平台,快速、开放、极简的 Web 开发框架
安装
$ npm i express
# 或
$ yarn add express
使用
见案例
应用生成器
express-generator
$ npx express-generator
RESTful
REST即表述性状态传递,是一套软件架构风格。是一组约束条件与原则,满足这些约束条件和原则的应用程序或设计就是RESTful。
资源与URI
任何事物,只要有被引用到的必要,它就是一个资源。资源可以是实体(例如手机号码),也可以只是一个抽象概念(例如价值) 。
要让一个资源可以被识别,需要有个唯一标识,在Web中这个唯一标识就是URI
统一资源接口
接口应该使用标准的HTTP方法如GET,PUT和POST,并遵循这些方法的语义。
- GET - 查询
- POST - 添加
- PUT - 修改
- DELETE - 删除
FormData
用于像表单一样处理key/value数据,可以方便的使用 XHR.send()
发送这种数据,如果编码类型被设为 "multipart/form-data"
,则可以发送文件数据。
const formData = new FormData()
formData.append(key, value)
formData.set(key, value)
Token
主要用于解决在跨域情况下,用户身份认证问题。用户登录成功后,服务端会生成 token,然后发送到前端进行保存,前端再请求服务端资源时,携带 token 数据发送回服务端实现认证,认证通过则继续响应正常操作,否则报错。
JWT - JSON Web Token
Socket 通信
TCP/IP
TCP:面向连接的协议,提供可靠数据传输
UDP:无连接,不保证数据传输的可靠性
IP:在网络中唯一标识设备
三次握手: 建立一个TCP连接时,需要客户端和服务端总共发送3个包以确认连接的建立
四次挥手: 终止TCP连接,就是指断开一个TCP连接时,需要客户端和服务端总共发送4个包以确认连接的断开。
Socket
HTTP 是单向的通信协议,是需要客户端主动发起请求,到达服务端后,在服务端进行响应,无法做到服务端主动向客户端发送消息。
Socket 是双向的通信协议,通信的双方都能主动向对方发送消息,也能接收对方发送的消息。
可以使用 “ajax 轮询” 的方式来实现客户端与服务端“双向通信”,获取实时数据。
服务端要做的事有这些:
Step 1:创建服务端Socket对象,绑定监听的端口
Step 2:调用方法监听客户端的请求,等待客户端连接
Step 3:连接建立后,通过输入流读取客户端发送的请求信息
Step 4:通过输出流向客户端发送响应信息
Step 5:关闭相关资源
客户端要做的事有这些:
Step 1:创建客户端Socket对象,指明需要链接的服务器的地址和端号
Step 2:链接建立后,通过输出流向服务器发送请求信息
Step 3:通过输入流获取服务器响应的信息
Step 4:关闭相关资源
WebSocket
WebSockets 是一种先进的技术。它可以在用户的浏览器和服务器之间打开交互式通信会话。使用此API,您可以向服务器发送消息并接收事件驱动的响应,而无需通过轮询服务器的方式以获得响应。
// 创建 WebSocket 对象
const socket = new WebSocket(url)
// 向服务器发送消息
socket.send(message)
// 接收服务器消息
socket.onmessage = function(event) {
// event.data
}
// 关闭释放资源
socket.close()
Socket.io
实现网络聊天程序
准备工作
- 创建项目目录,在项目下创建 package.json 文件:
$ mkdir chat
$ cd chat
$ npm init -y
- 安装 express
$ npm i express
- 创建 index.js(相当于是服务端):
const express = require('express');
const app = express();
const http = require('http');
const server = http.createServer(app);
app.get('/', (req, res) => {
res.send('<h1>Hello world</h1>');
});
server.listen(3000, () => {
console.log('listening on *:3000');
});
- 创建 index.html 文件(相当于客户端):
<!DOCTYPE html>
<html>
<head>
<title>Socket.IO chat</title>
<style>
body { margin: 0; padding-bottom: 3rem; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; }
#form { background: rgba(0, 0, 0, 0.15); padding: 0.25rem; position: fixed; bottom: 0; left: 0; right: 0; display: flex; height: 3rem; box-sizing: border-box; backdrop-filter: blur(10px); }
#input { border: none; padding: 0 1rem; flex-grow: 1; border-radius: 2rem; margin: 0.25rem; }
#input:focus { outline: none; }
#form > button { background: #333; border: none; padding: 0 1rem; margin: 0.25rem; border-radius: 3px; outline: none; color: #fff; }
#messages { list-style-type: none; margin: 0; padding: 0; }
#messages > li { padding: 0.5rem 1rem; }
#messages > li:nth-child(odd) { background: #efefef; }
</style>
</head>
<body>
<ul id="messages"></ul>
<form id="form" action="">
<input id="input" autocomplete="off" /><button>Send</button>
</form>
</body>
</html>
利用 Socket.io 实现聊天室
- 安装 socket.io 包:
$ npm install socket.io
socket.io 由两部分组件:服务端库与客户端库,在开发模式下,socket.io 中包含这两部分。
- 修改 index.js 与 index.html,创建服务端与客户端套接字:
// index.js
// 基于 http 服务器,创建服务端 Socket 对象
const io = new Server(server);
// 注册 connection 事件监听,等待客户端连接
// 当有客户端连接上来时,会执行回调函数
io.on('connection', (socket) => {
// socket 代表的就是连接到服务端的客户
console.log('a user connected');
});
<!-- index.html -->
<script src="/socket.io/socket.io.js"></script>
<script>
// 连接服务器,不传递参数时,默认以访问页面的 url 中的 host 为服务器地址
var socket = io();
</script>
- 发送与接收消息(事件)
在接收消息方,注册事件监听(自定义事件)用于接收消息。
在消息发送方,触发对应的事件(自定义事件)去发送消息。
服务端:
// 注册 connection 事件监听,等待客户端连接
// 当有客户端连接上来时,会执行回调函数
io.on('connection', (socket) => {
// socket 代表的就是连接到服务端的客户
console.log('a user connected');
// 向客户发送欢迎消息
socket.emit('clientReceive', '欢迎您!!!')
// 注册一个自定义事件监听,用于接收客户端发送过来的消息
socket.on('serverReceive', (msg) => {
console.log('message: ' + msg);
// 将接收到的该客户消息转发给每个连接到服务器的客户
io.emit('clientReceive', msg)
});
});
客户端:
<script>
// 连接服务器,不传递参数时,默认以访问页面的 url 中的 host 为服务器地址
var socket = io();
// 获取页面中 DOM 元素
var form = document.getElementById('form');
var input = document.getElementById('input');
var messages = document.getElementById('messages');
// 表单提交,向服务器发送消息
form.addEventListener('submit', function(e) {
// 阻止默认行为
e.preventDefault();
// 有输入内容,则触发在服务端注册的事件,发送消息
if (input.value) {
// 触发事件
socket.emit('serverReceive', input.value);
// 清空文本框
input.value = '';
}
});
// 注册事件监听,用于接收服务端发送的消息
socket.on('clientReceive', msg => {
// 创建 li 节点
var item = document.createElement('li');
// 设置节点文本内容
item.textContent = msg;
// item.innerHTML = msg;
// 将 li 节点追加到 ul 内部
messages.appendChild(item);
// 滚动到最后
window.scrollTo(0, document.body.scrollHeight);
})
</script>