【实践】使用NodeJS开发第一个命令行工具

同步更新 微信公众号【爱写代码的小任】 欢迎关注

背景

在工作中,内网中的服务,想要暴露出去(公网),给不在内网的伙伴访问。要实现这些,我归结一下几个常见的问题。

  1. 发现公司的公网IP是不固定的;
  2. 使用第三方花生壳面临收费,限速的问题;
  3. 若IP变更,对应的DNS解析也需要变化,同时如果能有通知(如钉钉)最好了
  4. 使用哪一个开发语言(技术栈)开发 能够更容易理解

解决方案准备

  1. 语言首选 Go,因为之前开发命令行工具, Go语言比较适合, 但其次考虑到语言理解度上, 最后还是选择的NodeJS,搜索了下,NodeJs相关的库也足够用了。

实施过程

1. 创建Node 命令行项目

# 1. 创建目录
$ mkdir  auto-change
# 2. 初始化
$ cd auto-change
$ npm init --yes
# 3. 创建 bin 目录
$ mkdir bin
$ vim bin/main.js
# 4. nodejs 启动 bin 下面是 package.json内容 主要是 bin那块的配置
{
  "name": "auto-change",
  "version": "1.0.0",
  "description": "",
  "bin": {
    "auto-change": "bin/main.js"
  },
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "dingding-robot-sdk": "^1.0.0",
    "nodejs-publicip": "^2.1.2"
  }
}

2. 使用获取公网IP的库


/**
 * 1. 获取公网IP https://blog.csdn.net/hua_thirteen/article/details/125016420
 */
async function main() {
    try {
        const ipAddress = await new PublicIp().queryPublicIPAddresses()
        let previousIp = readIpFromFile();
        
        if (ipAddress.ipv4 !== previousIp) {
            console.log(`捕获IP变更: ${previousIp} -- ${ipAddress.ipv4}`)
            const msgInfo = `优秀: 捕获IP地址变更 ${previousIp} -- ${ipAddress.ipv4}}`
            sendDingMsg(msgInfo)
            updateDnsRecord(ipAddress.ipv4);
        } else {
            console.log("IP没有变更, 不执行任何操作")
        }
        writeIpToFile(ipAddress.ipv4);
    } catch (error) {
        console.error(error);
    }
}

3. 使用文件库,主要用于记录变化前的IP地址

function readIpFromFile(){
    try {
        return fs.readFileSync("/tmp/auto-change.txt","utf-8");
    } catch (error) {
        console.error(error);
        return "";
    }
}

function writeIpToFile(ipv4){
    fs.writeFileSync("/tmp/auto-change.txt", ipv4);
}

4. 使用钉钉机器人库


/**
 * 钉钉消息回调 https://open.dingtalk.com/document/robots/custom-robot-access
 * https://gitee.com/yunsin/dingding_robot_sdk
 */
const webhookURL = "https://oapi.dingtalk.com/robot/send?access_token=";
async function sendDingMsg(msgInfo){
    try {
        const robot = new Robot(webhookURL);
        const sendRes = await robot.sendText({
            content: msgInfo,
            atMobiles: "",
            isAtAll: true,
        });
        console.log(`发送钉钉消息结果是: ${JSON.stringify(sendRes)}`);
    } catch (error) {
        console.error(error);
    }
}

5. 调用DNS解析库

这里主要是通过调用aliyun 命令行工具,更新DNS解析

/**
 * https://next.api.aliyun.com/api/Alidns/2015-01-09/UpdateDomainRecord
 * 3. 通过阿里云CLI命令修改解析即可
 */
const util = require('util');
const exec = util.promisify(require('child_process').exec);

async function updateDnsRecord(ipv4) {
    const dnsRecordArr = [];
    for(var i=0;i< dnsRecordArr.length;i++) {
        const dnsRecord = dnsRecordArr[i];
        try {
            const command = `aliyun alidns UpdateDomainRecord --profile dns --region cn-hangzhou --RecordId ${dnsRecord.recordId} --RR ${dnsRecord.rr} --Type A --Value '${ipv4}'`
            const { stdout, stderr } = await exec(command);
            console.log('stdout:', stdout);
            console.log('stderr:', stderr);
            await sleep(10000)
        } catch (error) {
            console.log("更新异常")
            console.error(error);
        }
    }
}

6. 配置定时任务

定时任务借助Linux自带的非常稳的 crontab实现

# 添加用户级的定时任务
$ crontab -e
# 追加一下内容,这里面需要注意,这里面的命令他不会调用环境变量, 需要手动让环境变量生效
27 11 * * * source $HOME/.bashrc && auto-change & >> ~/auto-change.out 2>&1

总结

通过以上代码,完整的实现了,公网IP地址变更, 造成DNS解析问题,间接实现了内网穿透的问题,这让我后面也不需要持续关注因为IP地址变更,造成每次手动修改DNS问题, 期望你读到这篇文章后,能有实质收获.

关注我,实时获取我的更新动态,和我一起讨论

  • 16
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱写代码的小任

感谢老板打赏,我将会再接再厉

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值