Nod.Js如何执行脚本,实时输出的实现方法是什么
Admin 2022-08-16 群英技术资讯 1198 次浏览
在实际应用中,我们有时候会遇到“Nod.Js如何执行脚本,实时输出的实现方法是什么”这样的问题,我们该怎样来处理呢?下文给大家介绍了解决方法,希望这篇“Nod.Js如何执行脚本,实时输出的实现方法是什么”文章能帮助大家解决问题。需要一个服务来执行shell脚本,要求可以实时打印shell脚本执行的过程,并看到脚本执行的结果。
这是一个web服务,需要执行shell脚本
当一个脚本执行的时候,再次发送请求需要等待当前脚本执行完毕,再自动执行这次请求
使用长连接而不是socket
添加脚本不需要重启服务器
这里采用的是express框架
新建app.js文件, npm install express
const express = require('express');
const app = express();
app.get('/:id', (req, res) => {
const { id } = req.params;
if (id === 'favicon.ico') {
res.sendStatus(200);
return;
}
// 执行脚本
});
app.set('port', 3018);
app.listen(app.get('port'), () => console.log(`server listening at ${app.get('port')}`));
新建config.json用于配置id和脚本名的对应关系,新建scripts目录用于存放脚本。
这里定义一个函数execute参数为id和response对象,代码如下:
const pidDict = {};
async function execute(id, res) {
delete require.cache[require.resolve('./config.json')];
const config = require('./config.json');
const filePath = config[id];
if (!filePath) {
res.sendStatus(404);
return;
}
console.log(`The script:${filePath} with ${id} begin execute`);
const readable = new Readable();
readable._read = () => {};
readable.pipe(res);
while (pidDict[id]) {
readable.push('\nWaiting for another script request.');
await wait(5000);
}
const handle = spawn('sh', [`./scripts/${filePath}`]);
pidDict[id] = handle.pid;
handle.stdout.on('data', (data) => {
readable.push(`\n${data}`);
getLogger(filePath).log(`\n${data}`);
});
handle.stderr.on('data', (data) => {
getLogger(filePath).warn(`\n${data}`);
readable.push(`\n${data}`);
});
handle.on('error', (code) => {
getLogger(filePath).error(`child process error with information: \n${code}`);
readable.push(`child process error with information: \n${code}`);
delete pidDict[id];
readable.push(null);
});
handle.on('close', (code) => {
getLogger(filePath).log(`child process close with code ${code}`);
delete pidDict[id];
readable.push(null);
});
}
解释:
首先要加载config.json,需要注意的是,因为是需要动态引入,所以这里不能直接使用require('config.json'),在这之前,需要先删除引入的缓存:delete require.cache[require.resolve('./config.json')];
获取文件路径 const filePath = config[id];
新建读写流,可以直接发送到前端。
再执行脚本前,需要判断当前有无脚本执行,这里在外部定义了一个pidDict,文件对应的id直接指向文件执行的handle的pid
紧接着就是输入输出流了
handle.stdout是标准输出
handle.stderr是错误输出,这里指的是输出的警告
handle的error事件指的是脚本执行中遇到的错误,也就是脚本执行不成功报的错误信息
这里定义了两个外部函数,一个是自定义的日志打印,另一个是遇到有脚本执行时的等待
新建utility.js
const fs = require('fs');
/**
* time wait
*
* @param time {number} time(ms) to wait
*/
/* eslint-disable compat/compat */
const wait = async (time = 1000) => {
return new Promise((resolve) => {
setTimeout(resolve, time);
});
};
/**
* set log
*
* getLogger(path).level
* level:
* log
* trace
* debug
* info
* warn
* error
* @param path
*/
function getLogger(path) {
return require('tracer').console({
transport: (data) => {
console.log(data.output);
fs.appendFile(`./logs/${path}.log`, `${data.rawoutput} \n`, () => {});
},
});
}
module.exports = {
wait,
getLogger,
};
现在,新建scripts/hello-world.sh
#!/bin/sh
echo 'hello...'
sleep 5
echo 'world!'
config.json中注册该脚本
{
"hello-world": "hello-world.sh"
}
执行node app.js,通过curl http://localhost:3018/hello-world即可观察到运行结果。
这里放上app.js的完整代码
const express = require('express');
const { spawn } = require('child_process');
const { Readable } = require('stream');
const { wait, getLogger } = require('./utility');
const app = express();
app.get('/:id', (req, res) => {
// 执行脚本
const { id } = req.params;
if (id === 'favicon.ico') {
res.sendStatus(200);
return;
}
execute(id, res).then();
});
const pidDict = {};
/**
* 执行sh脚本
*
* @param id 脚本id
* @param res response object
*/
/* eslint-disable no-underscore-dangle, no-await-in-loop */
async function execute(id, res) {
delete require.cache[require.resolve('./config.json')];
const config = require('./config.json');
const filePath = config[id];
if (!filePath) {
res.sendStatus(404);
return;
}
console.log(`The script:${filePath} with ${id} begin execute`);
const readable = new Readable();
readable._read = () => {};
readable.pipe(res);
while (pidDict[id]) {
readable.push('\nWaiting for another script request.');
await wait(5000);
}
const handle = spawn('sh', [`./scripts/${filePath}`]);
pidDict[id] = handle.pid;
handle.stdout.on('data', (data) => {
readable.push(`\n${data}`);
getLogger(filePath).log(`\n${data}`);
});
handle.stderr.on('data', (data) => {
getLogger(filePath).warn(`\n${data}`);
readable.push(`\n${data}`);
});
handle.on('error', (code) => {
getLogger(filePath).error(`child process error with information: \n${code}`);
readable.push(`child process error with information: \n${code}`);
delete pidDict[id];
readable.push(null);
});
handle.on('close', (code) => {
getLogger(filePath).log(`child process close with code ${code}`);
delete pidDict[id];
readable.push(null);
});
}
app.set('port', 3018);
app.listen(app.get('port'), () => console.log(`server listening at ${app.get('port')}`));
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:mmqy2019@163.com进行举报,并提供相关证据,查实之后,将立刻删除涉嫌侵权内容。
猜你喜欢
微信小程序的图片选择控件怎样实现?在使用微信小程序上传图片时,一般我们都需要用到图片选择控件,这样我们能比较便捷的从手机本地相差将图片上传到微信上,那么小程序的图片选择控件效果是如何实现的呢?下面我们一起来学习一下。
什么是Express中间件?Node中要怎么使用?下面本篇文章就来给大家介绍一下Express中间件的简单使用方法,希望对大家有所帮助!
这篇文章主要介绍了Vue的混合继承,有需要的朋友可以借鉴参考下,希望能够有所帮助,希望能够给你带来帮助
使用typescript类型实现ThreeSum 目录 前言 思路整理 实现TwoSum 实现减法 元祖中是否包含差值 递归元组 测试 实现ThreeSum 实现排序 实现ThreeSum 测试 前言 本文执行环境typescript,版本4.7.4 不使用typescript的计算能力,通过类型来实现ThreeSum 思路整理 实现ThreeSum之前我们先降低下难度,实现TwoSum,因为TwoSum可以作为ThreeSum的基础泛型 TwoSum需要准备什么呢? 递归元组,模拟for循环 减法,递归过程中求出差值 对每一项差值判断是否存在
笔者最近在做一些node端的文件读写和分片上传工作,在这个过程中,发现node读取的文件如果超过2G,超过了读取Blob最大值,会出现读取异常,此外在node中读写文件也受服务器RAM的限制等,需要分片读取,本人记录一下遇到的问题以及解决问题的经过。
成为群英会员,开启智能安全云计算之旅
立即注册关注或联系群英网络
7x24小时售前:400-678-4567
7x24小时售后:0668-2555666
24小时QQ客服
群英微信公众号
CNNIC域名投诉举报处理平台
服务电话:010-58813000
服务邮箱:service@cnnic.cn
投诉与建议:0668-2555555
Copyright © QY Network Company Ltd. All Rights Reserved. 2003-2020 群英 版权所有
增值电信经营许可证 : B1.B2-20140078 ICP核准(ICP备案)粤ICP备09006778号 域名注册商资质 粤 D3.1-20240008