在express框架中实现调用系统命令并生成、下载压缩文件

目标

使用nodejs的express框架完成一个rest接口,调用一个go语言编写的工具生成两个文件(为啥用go写这个工具,因为不会用js写),返回给前端一个压缩包,并对文件内容做一些业务处理。

调用

使用child_process包,更多官方文档

const {spawn} = require('child_process');

const cmd = 'tools/finca';  
let args = ['-type=root'];

  let ls_root = spawn(cmd, args);

  ls_root.stdout.on('data', (data) => {
    logger.info(`stdout: ${data}`);
  });

  ls_root.stderr.on('data', (data) => {
    logger.error(`stderr: ${data}`);
  });

  ls_root.on('close', (code) => {
      logger.info(`finca tool process exited with code ${code}`);
  });

压缩

使用jszip包,官网,有时候会被墙。

const JSzip = require('jszip');
let zip = new JSzip();
zip.file(caRequest.commonName + "-cert.pem", CAResult.cert);
zip.file(caRequest.commonName + ".key", CAResult.privateKey);
let data = zip.generate({base64: false, compression: 'DEFLATE'});

文件夹删除

工具生成的文件和压缩文件均不保存,所有全部放在一个临时文件夹,结束后删除。

function deleteFolder(path) {
  let files = [];
  if (fs.existsSync(path)) {
    files = fs.readdirSync(path);
    files.forEach(function (file, index) {
      let curPath = path + "/" + file;
      if (fs.statSync(curPath).isDirectory()) { // recurse
        deleteFolder(curPath);
      } else { // delete file
        fs.unlinkSync(curPath);
      }
    });
    fs.rmdirSync(path);
  }
}

实现rest接口

这里最重要的是保证顺序执行

util

工具放在特定目录,一共生成了两个可执行文件,其中一个为.exe,方便在window环境下调试。调试时无需更改cmd,child_process调用时自动会根据操作系统调用.exe文件。

const {spawn} = require('child_process');
const fs = require("fs");
const Promise = require("bluebird");
const os = require('os');
const JSzip = require('jszip');

const certFileSuffix = "-cert.pem";
const priFileSuffix = "_sk";
const cmd = 'tools/finca';
let caUtil = {};

caUtil.createRootCA = function (caRequest, res) {
  let args = ['-type=root'];
  return createCA(caRequest, args, res);
};

caUtil.createClientCA = function (caRequest, res, rootCertBase64String, rootPrivateKeyBase64String, base64PublicKeyString) {
  let args = ['-type=client'];
  if (rootCertBase64String && rootPrivateKeyBase64String) {
    args.push('-rootCert=' + rootCertBase64String);
    args.push('-rootPri=' + rootPrivateKeyBase64String);
  } else {
    return Promise.reject('miss root CA')
  }
  return createCA(caRequest, args, res, base64PublicKeyString);
};

function createCA(caRequest, args, res, base64PublicKeyString) {
  let exitPubKey = false;
  let CAResult = {
    privateKey: '',
    cert: ''
  };
  let dir;
  if (base64PublicKeyString) {
    logger.info("public exit,do not create private key");
    exitPubKey = true;
    args.push('-clientPub=' + base64PublicKeyString)
  }
  if (caRequest.commonName) {
    args.push('-cn=' + caRequest.commonName);
    dir = os.tmpdir() + '/' + caRequest.commonName + '/';
    args.push('-dir=' + dir);
  } else {
    return Promise.reject("miss commonName")
  }
  if (caRequest.country) {
    args.push('-c=' + caRequest.country);
  }
  if (caRequest.effectiveDays) {
    args.push('-day=' + caRequest.effectiveDays);
  }
  if (caRequest.locality) {
    args.push('-l=' + caRequest.locality);
  }
  if (caRequest.organization) {
    args.push('-o=' + caRequest.organization);
  }
  if (caRequest.organizationalUnit) {
    args.push('-ou=' + caRequest.organizationalUnit);
  }
  if (caRequest.province) {
    args.push('-p=' + caRequest.province);
  }
  if (caRequest.role) {
    args.push('-role=' + caRequest.role);
  }
  logger.info("create CA args:", args);
  let ls_root = spawn(cmd, args);

  ls_root.stdout.on('data', (data) => {
    logger.info(`stdout: ${data}`);
  });
  ls_root.stderr.on('data', (data) => {
    logger.error(`stderr: ${data}`);
  });
  return new Promise(function (accept, reject) {
    ls_root.on('close', (code) => {
      logger.info(`finca tool process exited with code ${code}`);
      if (code === 0) {
        CAResult.cert = fs.readFileSync(dir + caRequest.commonName + certFileSuffix);
        if (!exitPubKey) {
          CAResult.privateKey = fs.readFileSync(dir + caRequest.commonName + priFileSuffix);
        }
        if (res) {
          logger.info(`do zip`);
          let zip = new JSzip();
          zip.file(caRequest.commonName + "-cert.pem", CAResult.cert);
          if (!exitPubKey) {
            zip.file(caRequest.commonName + ".key", CAResult.privateKey);
          }
          let data = zip.generate({base64: false, compression: 'DEFLATE'});
          res.set({
            'Content-Type': 'application/vnd.openxmlformats',
            "Content-Disposition": "attachment; filename=" + caRequest.commonName + ".zip"
          });
          res.end(data, 'binary');
        }
        logger.info(`ca tool work done, delete temp dir`);
        deleteFolder(dir);
        accept(CAResult);
      } else {
        reject("create CA error with code:", code)
      }
    })
  })
}

function deleteFolder(path) {
  let files = [];
  if (fs.existsSync(path)) {
    files = fs.readdirSync(path);
    files.forEach(function (file, index) {
      let curPath = path + "/" + file;
      if (fs.statSync(curPath).isDirectory()) { // recurse
        deleteFolder(curPath);
      } else { // delete file
        fs.unlinkSync(curPath);
      }
    });
    fs.rmdirSync(path);
  }
}

module.exports = caUtil;

route

const express = require('express');
const router = express.Router();
const caUtil = require('../utils/caUtil');

router.post('/register', function (req, res, next) {
  let promise= caUtil.createRootCA(req.body,res);
  promise.then(CAResult=>{
    console.log("这里做一些业务相关操作",CAResult);
  })
});

module.exports = router;

最后app.js添加引用

mocha测试框架

const app = require("../app.js");
const supertest = require("supertest");
const should = require('should');
const request = supertest(app);
const caReq={
  commonName:"test.orgTest.cn",
  country:"CN",
  locality:"GuangDong",
  province:"ShenZhen",
  effectiveDays:365,
  organization:"xxxxx.orgTest.cn",
  organizationalUnit:"xxxxx",
  role:"admin"
};

describe('===组织管理测试===', function (done) {
  it("---组织注册成功---",function(done){
    request.post('/org/register')
      .send(caReq)
      .end(function (err, res) {
        console.log(res.body);
        done();
      });
  });
});

这个测试看不出来下载效果,测试代码逻辑比较方便。可以启动项目用postman点击Send And Download试一下下载压缩文件即可。

 

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
由于JavaScript是一种在浏览器端运行的脚本语言,它没有直接调用本地安装软件的能力。因此,要在JavaScript实现rar文件的解压,需要借助服务端的支持。以下是一种可能的实现方式: 1. 在服务端安装WinRAR,并确保WinRAR可执行文件所在路径已经被添加到系统环境变量。 2. 使用Node.js搭建一个Web应用程序,在其编写一个路由处理程序,用于处理解压请求。例如: ```javascript const express = require('express'); const child_process = require('child_process'); const app = express(); app.get('/unrar', (req, res) => { const rarFilePath = req.query.rarFilePath; // 获取请求参数的rar文件路径 const outputDirPath = req.query.outputDirPath; // 获取请求参数的输出目录路径 // 使用child_process模块调用WinRAR解压rar文件 const cmd = `unrar e "${rarFilePath}" "${outputDirPath}"`; child_process.exec(cmd, (error, stdout, stderr) => { if (error) { console.error(`exec error: ${error}`); res.status(500).send('解压失败'); } else { console.log(`stdout: ${stdout}`); console.error(`stderr: ${stderr}`); res.send('解压成功'); } }); }); app.listen(3000, () => { console.log('Server is up and running on port 3000'); }); ``` 3. 在客户端使用ajax或fetch等工具向服务器发起解压请求,将rar文件路径和输出目录路径作为请求参数传递给服务器。例如: ```javascript // 使用jQuery的ajax方法发送解压请求 $.ajax({ url: '/unrar', data: { rarFilePath: 'C:/test.rar', outputDirPath: 'C:/output' }, success: (result) => { console.log(result); // 输出解压结果 }, error: (xhr, status, error) => { console.error(error); // 输出错误信息 } }); ``` 注意:由于WinRAR是一个商业软件,需要购买正版授权才能合法使用。在实际应用,还需要考虑安全性、权限控制等问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值