美文网首页
基于NodeJS的简易DDNS

基于NodeJS的简易DDNS

作者: dsjaikdnsajdnua | 来源:发表于2019-04-27 11:16 被阅读0次

无意间看到腾讯云的API文档,发现提供修改解析记录的接口。然后在想能否搭建一个非常简易的小程序,用于修改域名的解析记录呢?经过试验,是没问题的。文章的所有的代码

思路

  • 使用NodeJS编写一个简易的服务端,验证来自于客户端的请求之后,然后调用腾讯的api将对应的三级域名的解析修改成最新的IP。
  • 简易的流程图如下: 请求的流程图
  • 实现思路。原来,我想法很简单,就直接在路由器使用脚本发起修改解析的请求。后来,我想可以做一个服务端,用于响应多个客户端的请求,可以添加或者修改解析记录,这样就可以用于多台的设备了。
  • 校验请求。既然多个客户端,那么校验是需要的,所以可以使用静态文件配置token对应3级域名,或者存放与数据库中,恰好,我原本就安装了Mysql数据库,所以我就基于Mysql来存放我的配置内容吧。然后下面就是使用nodejs实现的过程了。

代码实现

!!如果你嫌麻烦,可以直接跳转代码地址。github

调试腾讯云API
  • 查看了腾讯云的API文档,发现不仅仅简单的发送参数和SecretId和SecretKey就可以了完成请求了,api的公共参数还需要一个签名,所以我们需要先计算出每一次请求的签名值。我也没找到官方提供计算签名的工具或者代码,所以自己在浏览器的控制台实现吧。
  • 计算签名。这个过程遇到了比较多的问题,因为我并没有非常仔细的阅读文档。下面是签名的算法:

代码注释里面写了注意的事项,都是有可能造成调用api失败。

/**
* 注意:
* 1. 算的签名必须要经过encodeURIComponent编码。
* 2. 检查请求的地址有没有错
* 3. 检查请求的action有没有错
* 4. 检查时间戳有没有过期
* 5. 默认为Get请求,请使用get请求。使用encodeSignature作为Signature参数
* 6. 排序的时候大小写敏感了。使用原生的排序即可
* 7. 官网例子:parseUrl("https://cns.api.qcloud.com/v2/index.php?Action=DescribeInstances&InstanceIds.0=ins-09dx96dg&Nonce=11886&Region=ap-guangzhou&SecretId=AKIDz8krbsJ5yKBZQpn74WFkmLPx3gnPhESA&SignatureMethod=HmacSHA256&Timestamp=1465185768","Gu5t9xGARNpq86cd98joQYCN3Cozk1qA",[]);、
    返回:0EEm/HtGRr/VJXTAD9tYMth1Bzm3lLHz5RCDv1GdM8s=
    编码:0EEm%2FHtGRr%2FVJXTAD9tYMth1Bzm3lLHz5RCDv1GdM8s%3D
* @param {*} url 除了Signature参数以外的get请求字符串。如:https://cns.api.qcloud.com/v2/index.php?Action=DescribeInstances&InstanceIds.0=ins-09dx96dg&Nonce=11886&Region=ap-guangzhou&SecretId=AKIDz8krbsJ5yKBZQpn74WFkmLPx3gnPhESA&SignatureMethod=HmacSHA256&Timestamp=1465185768
* @param {*} key 你的SecretId
* @param {*} result 传入一个数组。因为这里只有一个方法,需要请求加密的js,是异步的,不能将结果直接返回给你。通过数组将结果传递出去
* @returns 返回一个对象:
    {
        encodeSignature --编码后的签名(你需要的是这个)
        Signature --计算的签名
        href --你传递的地址
        param --解析出来的查询参数
        paramKeys --解析出来的查询参数的key
        paramSort --参数的排序(原生的js排序)
        paramJoins --参数的字符串
        paramJoin --
        joinAllGet --排序后的拼接请求字符串
    }
*/
function parseUrl(url, key, resultArr) {
    var addressConfig = {
        "RecordCreate": "cns.api.qcloud.com",//添加解析记录
        "RecordStatus": "cns.api.qcloud.com",//设置解析记录状态
        "RecordModify": "cns.api.qcloud.com",//修改解析记录
        "RecordList": "cns.api.qcloud.com",//获取解析记录列表
        "RecordDelete": "cns.api.qcloud.com",//删除解析记录
        "DescribeInstances": "cvm.api.qcloud.com"//查看实例列表
    };
    function _parser(url) {
        var result = {};
        var parser = document.createElement('a');
        parser.href = result.href = url;
        try {
            if (parser.search) {
                var param = parser.search.slice(1, parser.search.length);
                if (param) {
                    var paramArr = param.split("&");
                    if (paramArr) {
                        parser.param = result.param = {};
                        parser.paramKeys = result.paramKeys = paramArr.map(function (v) {
                            var vt = v.split("=");
                            parser.param[vt[0]] = result.param[vt[0]]   = vt.length === 2 ? vt[1] : "";
                            return vt[0];
                        });
                        parser.paramSort = result.paramSort = {};
                        /*1. 对参数排序 需要忽略大小写*/
                        parser.paramJoins = result.paramJoins = parser.paramKeys.sort().map(function (v) {
                            var value = decodeURIComponent(parser.param[v]);
                            parser.paramSort[v] = result.paramSort[v] = value;
                            return v + "=" + value;
                        });
                        /*2. 拼接请求字符串*/
                        parser.paramJoin = result.paramJoin = parser.paramJoins.join("&");
                        /*3. 拼接签名原文字符串 请求方法 + 请求主机 +请求路径 + ? + 请求字符串*/
                        parser.joinAllGet = result.joinAllGet = "GET" + (addressConfig[parser.param.Action]) + "/v2/index.php?" + parser.paramJoin;
                        /*4. 生成签名串*/
                        var hash = CryptoJS.HmacSHA256(parser.joinAllGet, key);
                        var hashInBase64 = CryptoJS.enc.Base64.stringify(hash);
                        parser.Signature = result.Signature = hashInBase64;
                        parser.encodeSignature = result.encodeSignature = encodeURIComponent(hashInBase64);
                    }
                }
            }
        } catch (error) {
            console.log("解析地址出错!");
            console.log(error);
        }
        return result;
    }
    $.getScript("https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/hmac-sha256.js", function () {
        $.getScript("https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/components/enc-base64-min.js", function () {
            var _result = _parser(url);
            resultArr.push(_result);
            console.log(resultArr);
        });
    });
}

如何运行这段代码呢?很简单,打开浏览器的控制台,整段复制进去,回车,会产生一个全局的方法:parseUrl。然后再在控制台调用parseUrl,参数在代码注释里面说的很清楚了,也有例子,返回的对象的encodeSignature属性就是你最终的签名值了
使用上述代码计算出签名值,然后再调用腾讯api,看看能否调试通过。通过就可以进行服务端的编写了。

服务端编码

我也很少接触nodejs。所以也写详细一点,也当做是自己的学习笔记。准备环境有:nodejs,mysql数据库(非必须,你可以把配置以及验证信息放到一个配置文件里面)。

  • 初始化项目。建立文件夹,node-ddns。运行:npm init。按照常规的输入内容。入口为app.js
  • 添加依赖。根据我们需求,需要2个依赖:express(用于处理请求)、mysql(用于连接、查询mysql数据库)。运行命令:
    npm install express --save
    npm install mysql --save
    
    以上完成后,package.json文件大概是以下内容:
    {
    "name": "node-ddns",
    "version": "1.0.0",
    "description": "",
    "main": "app.js",
    "scripts": {
      "test": "echo \"Error: no test specified\" && exit 1"
    },
    "author": "alan",
    "license": "ISC",
    "dependencies": {
      "express": "^4.16.4",
      "mysql": "^2.17.1"
    }
    }
    
    稍等片刻,就可以安装完毕了。如果出现错误,可以尝试使用管理员运行以上命令
  • 编写测试接口,连接mysql数据库。我们在app.js可以写下代码了。引入express和mysql依赖。非常简单,内容如下,意思是程序运行在3000端口,并且有一个/test的接口,返回“测试成功”字样:
var express = require('express');
var mysql = require("mysql");
var app = express();
var connection = mysql.createConnection({
  "host" : "111.230.165.16",
  "user" : "root",
  "password" : "alan@MYSQL!@#",
  "database" : "test"
});
connection.connect(function(err){
  if(err){
      console.log(err);
  }
});
app.get('/test',function(req,resp){
  connection.query("select 1 from dual",function(error,results,fields){
      if(error){
          resp.send('测试失败');
      }else{
          resp.send('测试成功');
      }
  });
});
app.listen(3000);
console.log("running on 3000");

运行命令:node app,应用启动,然后再浏览器访问,就可以看到以下内容

image.png
建立表结构。

这里是表结构创建的语句

表结构用于存放验证信息(ddns_user)和腾讯的token。
创建工具类
创建API文件

相关文章

网友评论

      本文标题:基于NodeJS的简易DDNS

      本文链接:https://www.haomeiwen.com/subject/nwshnqtx.html