安装及配置Node.js
安装Node.js
1、安装node版本控制插件
npm install n -g
2.安装指定版本
sudo n v14.15.0
3.进入用户目录,找到.bashrc文件,文件末尾添加以下代码(例如/usr/.bashrc)
#在文件末尾添加如下行(bin目录下只要有node可执行文件就行)
export PATH="/usr/local/n/node/bin:$PATH"
4.安装npm(Node包管理器)
sudo npm install -g npm
5.安装serve组件
npm install -g serve
6.安装Express框架
npm install express body-parser
配置Node.js
注:配置Node.js并设置持续监听某一端口,以及开机自动运行。
一、创建一个名为server.js的node.js文件用来监听处理前端传来的请求
//这是一个完整的node.js文件
const express = require('express');
const bodyParser = require('body-parser');
// 添加这一行以引入fs模块
const fs = require('fs');
// 创建Express应用实例
const app = express();
// 设置允许跨域访问的中间件(要处理post请求必须要有该代码)
app.use((req, res, next) => {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, DELETE');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
res.setHeader('Access-Control-Allow-Credentials', true);
// 对于预检OPTIONS请求,直接返回200
//(前端访问后端时都会先发一个预检请求,预检返回200时才会真正访问后端
if (req.method === 'OPTIONS') {
return res.sendStatus(200);
}
next();
});
// 使用body-parser解析JSON请求体
app.use(bodyParser.json());
//设置一个处理POST请求的路由,前端访问后端http填写则需要“ip:2000/api/abc”的形式
app.post('/api/abc', (req, res) => {
// 获取前端发送过来的JSON数据
const jsonData = req.body;
// 定义存储文件的路径和名称,这里使用绝对路径
const filePath = '/var/www/html/a/save/';
// 将JSON对象转换为字符串并写入文件
try {
//在服务器指定路径保存文件
fs.writeFileSync(filePath, JSON.stringify(jsonData, null, 2), 'utf8');
//返回一个值200给前端,告诉前端后端接收到了数据
res.status(200).json({ message: 'data-ok' });
} catch (err) {
res.status(500).json({ error: 'Internal server error while saving data' });
}
});
//监听2000端口
const PORT = process.env.PORT || 2000;
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`);
});
二、CD进入server.js文件所在的目录,安装express
sudo npm install express
三、CD进入server.js文件所在的目录,运行server.js
注:如果是云服务器,记得去云平台安全组放开node监听的端口。
node service.js
四、将node.js文件设置为开机自动运行且保持后台
注:如果要开机启动多个node.js,就要新建多个.service服务,并且针对配置。
1.安装nano:
sudo yum install -y nano
2.创建systemd服务文件:
注:my-node-app
为你要创建的服务文件名。
sudo nano /etc/systemd/system/my-node-app.service
3.填写服务文件内容:
[Unit]
//描述你的Node.js应用。例如:Description=My Node.js Web Server
Description=server.js Web Server
//表示该服务应在哪个目标后启动。network.target表示在网络接口初始化完成后启动此服务
After=network.target
[Service]
//此为你的node.js文件路径
ExecStart=/usr/bin/node /path/to/your/server.js
//设置服务重启策略。Restart=always 表示如果服务停止,则自动重启
Restart=always
//此为用什么用户运行该服务
User=user
//此为用什么用户组运行该服务
Group=user
//如果需要设置环境变量,这里可以添加。
//例如,如果你希望在生产环境中运行,设置 NODE_ENV=production。
Environment=NODE_ENV=production
[Install]
//这里指定当系统进入哪种运行级别或目标时,应该启动此服务。
//multi-user.target代表多用户命令行模式(无图形界面)。
//表示在系统启动到多用户状态后启动此服务。
WantedBy=multi-user.target
注:保存并退出 nano 编辑器:按 Ctrl + X 键,然后按 Y 键确认保存更改,最后按 Enter 键退出编辑器。
4.更新systemd配置:
sudo systemctl daemon-reload
5.启用新服务:
sudo systemctl enable server.service
6.启动服务:
sudo systemctl start server.service
7.查看服务运行状态:
systemctl status server.service
8.查看服务日志:
journalctl -u server.service
Node.js学习心得
用户访问HTML,HTML调用js,js发出POST请求向服务器提交数据,此时服务器上的node.js文件是如何运行的呢?
答:在用户访问HTML页面,页面中的js发出POST请求提交数据时,服务器端的Node.js已经启动并监听特定端口以接收这些请求。
+-------------------------+ +-----------------------+
| 用户浏览器 | | Node.js服务器 |
+-------------------------+ +-----------------------+
| |
| 1. 访问HTML页面 |
|-------------------------->|
| |
| 2. HTML页面加载JS脚本 |
|<---------------------------|
| |
| 3. JS脚本发起POST请求 |
|-------------------------->|
| (携带数据:如JSON、表单) |
| |
| 4. 请求到达Node.js服务器 |
| |
| 5. Node.js使用HTTP模块(如Express)监听端口 |
| |
| 6. 请求与处理中间件匹配 |
| |
| 7. Node.js解析POST数据 |
| |
| 8. 执行业务逻辑(如数据库操作)|
| |
| 9. Node.js构建响应内容 |
|<---------------------------|
| |
|10. 响应返回至浏览器 |
| |
+-------------------------+ +-----------------------+
Node.js常用功能代码
获取并本地存储前端传输的数据
注:监听前端post方式向后端node指定端口发送数据的请求,并将数据接收处理后存储服务器本地文件
//这是一个完整的node.js文件
const express = require('express');
const bodyParser = require('body-parser');
// 添加这一行以引入fs模块
const fs = require('fs');
// 创建Express应用实例
const app = express();
// 设置允许跨域访问的中间件(要处理post请求必须要有该代码)
app.use((req, res, next) => {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, DELETE');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
res.setHeader('Access-Control-Allow-Credentials', true);
// 对于预检OPTIONS请求,直接返回200
//(前端访问后端时都会先发一个预检请求,预检返回200时才会真正访问后端
if (req.method === 'OPTIONS') {
return res.sendStatus(200);
}
next();
});
// 使用body-parser解析JSON请求体
app.use(bodyParser.json());
//设置一个处理POST请求的路由,前端访问后端http填写则需要“ip:2000/api/abc”的形式
app.post('/api/abc', (req, res) => {
// 获取前端发送过来的JSON数据
const jsonData = req.body;
// 定义存储文件的路径和名称,这里使用绝对路径
const filePath = '/var/www/html/a/save/';
// 将JSON对象转换为字符串并写入文件
try {
//在服务器指定路径保存文件
fs.writeFileSync(filePath, JSON.stringify(jsonData, null, 2), 'utf8');
//返回一个值200给前端,告诉前端后端接收到了数据
res.status(200).json({ message: 'data-ok' });
} catch (err) {
res.status(500).json({ error: 'Internal server error while saving data' });
}
});
//监听2000端口
const PORT = process.env.PORT || 2000;
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`);
});
模拟shell执行指令并解析结果
const express = require('express');
const bodyParser = require('body-parser');
const fs = require('fs');// 添加这一行以引入fs模块,用于写入文件
const { exec } = require('child_process');// 添加这一行以引入child_process模块,用于模拟shell执行指令读取虚拟内存信息
// 创建Express应用实例
const app = express();
// 设置允许跨域访问的中间件(要处理post请求必须要有该代码)
app.use((req, res, next) => {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, DELETE');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
res.setHeader('Access-Control-Allow-Credentials', true);
// 对于预检OPTIONS请求,直接返回200(前端访问后端时都会先发一个预检请求,预检返回200时才会真正访问后端
if (req.method === 'OPTIONS') {
return res.sendStatus(200);
}
next();
});
//如果监听到前端查询磁盘信息的请求,走这里处理
// 设置一个处理POST请求的路由,前端访问后端http填写则需要“ip/api/a”的形式
app.post('/api/a', (req, res) => {
//模拟shell执行指令读取磁盘信息
function getVirtualMemoryInfo(callback) {
exec('df -k /dev/vda1', (error, stdout, stderr) => {
if (error) {
return;
}
//对shell执行后读取到的硬盘信息进行处理解析
const lines = stdout.split('\n');
const memoryInfoLine = lines[1];//只解析df -k执行后结果的第一行
//分割并提取相关信息
const memoryData = memoryInfoLine.trim().split(/\s+/);
const totaldisk = memoryData[1]; // 磁盘总容量,即第1行1列
const useddisk = memoryData[2]; // 磁盘已用空间,即第1行2列
const zhanyongdisk = memoryData[4]; // 磁盘占用率,即第1行4列
//返回执行的结果
callback(null, totaldisk, useddisk,zhanyongdisk);
});
}
//使用回调函数接收shell执行指令读取解析后的硬盘信息结果
getVirtualMemoryInfo((err, total_disk_, used_disk_,zydisk) => {
if (!err) {
const total_disk = (total_disk_ / 1024 / 1024 ).toFixed(2);
const used_disk = (used_disk_ / 1024 / 1024 ).toFixed(2);
console.log('磁盘总容量:', total_disk);
console.log('磁盘已用空间:', used_disk);
console.log('磁盘占用率:', zydisk);
//将获取到的数据整合到一个变量,稍后转换为json
const data = { total_disk,used_disk,zydisk};
//定义存储文件的路径和名称
const filePath = '/var/www/html/a' + '.json';
//将获取到的内存信息以json形式保存至本地/var/www/html/a.json
try {
//在服务器指定路径保存文件
fs.writeFileSync(filePath, JSON.stringify(data, null, 2), 'utf8');
res.status(200).json({ message: 'data-ok' });
} catch (err) {
console.error('Caught an error while saving file:', err);
res.status(500).json({ error: 'Internal server error while saving data' });
}
}
});
});
查询系统内存信息
//如果是查询内存信息post,走这里处理
// 设置一个处理POST请求的路由,前端访问后端http填写则需要“/me”的形式
app.post('/me', (req, res) => {
//----------
//模拟shell执行指令读取虚拟内存信息
function getVirtualMemoryInfo(callback) {
exec('free -m', (error, stdout, stderr) => {
if (error) {
console.error(`执行命令出错: ${error}`);
return;
}
// 解析 'free' 命令的输出
const lines = stdout.split('\n');
const memoryInfoLine = lines[2]; //获取虚拟内存信息
const MemoryBytes = lines[1]; //获取物理内存信息
// 分割并提取相关信息
const memoryData = memoryInfoLine.trim().split(/\s+/);
const MemoryBytesData = MemoryBytes.trim().split(/\s+/);
const totalVirtualMemory = memoryData[1]; // 总虚拟内存(含swap)
const usedVirtualMemory = memoryData[2]; // 已用虚拟内存(含swap)
const totalPhysicalMemoryBytes = MemoryBytesData[1]; //总物理内存
const freePhysicalMemoryBytes = MemoryBytesData[2]; //已用物理内存
//返回执行的结果
callback(null, totalVirtualMemory, usedVirtualMemory,totalPhysicalMemoryBytes,freePhysicalMemoryBytes);
});
}
//使用回调函数接收shell执行指令读取虚拟内存信息的结果
getVirtualMemoryInfo((err, totalVirtualMemory, usedVirtualMemory,totalPhysicalMemoryBytes,freePhysicalMemoryBytes) => {
/将获取到的数据整合到一个变量,稍后转换为json
const data = { totalVirtualMemory,usedVirtualMemory,totalPhysicalMemoryBytes,freePhysicalMemoryBytes };
// 定义存储文件的路径和名称
const filePath = '/a/me' + '.json';
//----------
//将获取到的内存信息以json形式保存至本地/a/me.json
try {
//在服务器指定路径保存文件
fs.writeFileSync(filePath, JSON.stringify(data, null, 2), 'utf8');
//----------
console.log('JSON data saved successfully to:', filePath);
//----------
res.status(200).json({ message: 'data-ok' });
} catch (err) {
console.error('Caught an error while saving file:', err);
res.status(500).json({ error: 'Internal server error while saving data' });
}
});
//----------
});
查询CPU信息
const express = require('express');
const bodyParser = require('body-parser');
const osu = require('node-os-utils');//引入此模块读取cpu占用率
const cpu = osu.cpu; //引入此模块读取cpu占用率
// 创建Express应用实例
const app = express();
// 设置允许跨域访问的中间件(要处理post请求必须要有该代码)
app.use((req, res, next) => {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, DELETE');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
res.setHeader('Access-Control-Allow-Credentials', true);
// 对于预检OPTIONS请求,直接返回200(前端访问后端时都会先发一个预检请求,预检返回200时才会真正访问后端
if (req.method === 'OPTIONS') {
return res.sendStatus(200);
}
next();
});
//如果是查询内存信息post,走这里处理
// 设置一个处理POST请求的路由,前端访问后端http填写则需要“ip/api/cpu”的形式
app.post('/api/cpu', (req, res) => {
// 获取CPU使用率
const usage = await cpu.usage();
});
查询系统关键服务运行状态及占用内存
app.post('/a/sys', async (req, res) => {
//要添加监察的服务在这里添加
const services = ['halo', 'ydzs', 'ydzs_jianfei', 'nginx', 'docker'];
let data = [];
//----------
for (const serviceName of services) {
try {
let stdout = '';
let stderr = '';
let memoryUsage = null; //定义存储服务物理内存数值的变量
let memoryUsage_xn = null; //定义存储服务物理内存数值的变量
//----------
//获取服务占用物理内存
try {
//调用该方法进行获取占用物理内存,并传出数值
memoryUsage = await getMemoryUsageByService(serviceName);
} catch (memoryError) {
console.error(`获取服务 ${serviceName} 内存占用时出错: ${memoryError}`);
memoryUsage = null; // 设置为无效值或默认值
}
//获取服务占用虚拟内存
try {
memoryUsage_xn = await getMemoryUsageByService_xn(serviceName);
} catch (memoryError) {
console.error(`获取服务 ${serviceName} 内存占用时出错: ${memoryError}`);
memoryUsage = null; // 设置为无效值或默认值
}
//----------
//获取服务运行状态
const result = await new Promise((resolve, reject) => {
exec(`systemctl is-active ${serviceName}`, (error, out, err) => {
if (error) {
//服务如果获取失败异常停止运行也要保存状态信息
data.push({
serviceName,
isActive: false,
memoryUsage,
memoryUsage_xn,
});
resolve();
return;
}
stdout = out;
stderr = err;
//----------
//将获取到的服务状态和服务内存占用存入data变量
data.push({
serviceName,
isActive: stdout.trim() === 'active',
memoryUsage,
memoryUsage_xn,
});
resolve();
});
});
if (stderr) {
console.error(`${serviceName}: 服务名称不正确`);
}
//----------
} catch (error) {
console.error(`Error checking service ${serviceName}: ${error}`);
}
}
//----------
// 保存结果
try {
const filePath = '/a/data.json';
fs.writeFileSync(filePath, JSON.stringify(data, null, 2), 'utf8');
console.log('JSON data saved successfully to:', filePath);
//----------
// 一次性发送HTTP响应
res.status(200).json({ message: 'data-ok', services: data });
} catch (writeErr) {
console.error('Caught an error while saving file:', writeErr);
res.status(500).json({ error: 'Internal server error while saving data' });
}
//----------
});
//----------
//----------
//----------
//----------
//获取指定名称的服务运行物理内存大小,如果有多个同名进程,将内存相加输出
function getMemoryUsageByService(serviceName) {
return new Promise((resolve, reject) => {
// 执行系统命令
exec(`ps aux | grep ${serviceName}`, (error, stdout, stderr) => {
if (error) {
reject(error);
return;
}
//----------
// 解析命令输出结果
const outputLines = stdout.split('\n');
let totalMemoryUsageKB = 0;
//----------
outputLines.forEach(line => {
const columns = line.split(/\s+/);
const memoryUsage = parseInt(columns[5]);
if (!isNaN(memoryUsage)) {
totalMemoryUsageKB += memoryUsage;
}
});
//----------
let memoryUsageGB = totalMemoryUsageKB / 1024 / 1024;
memoryUsageGB = memoryUsageGB.toFixed(2); // 保留两位小数
resolve(memoryUsageGB);
});
});
}
//----------
//----------
//获取指定名称的服务运行虚拟内存大小,如果有多个同名进程,将内存相加输出
function getMemoryUsageByService_xn(serviceName) {
return new Promise((resolve, reject) => {
// 执行系统命令
exec(`ps aux | grep ${serviceName}`, (error, stdout, stderr) => {
if (error) {
reject(error);
return;
}
//----------
// 解析命令输出结果
const outputLines = stdout.split('\n');
let totalMemoryUsageKB = 0;
//----------
outputLines.forEach(line => {
const columns = line.split(/\s+/);
const memoryUsage = parseInt(columns[4]);
if (!isNaN(memoryUsage)) {
totalMemoryUsageKB += memoryUsage;
}
});
//----------
let memoryUsageGB_xn = totalMemoryUsageKB / 1024 / 1024;
memoryUsageGB_xn = memoryUsageGB_xn.toFixed(2); // 保留两位小数
resolve(memoryUsageGB_xn);
});
});
}
评论区