为什么此代码中的表单DOM对象值未更新?

时间:2019-06-25 17:38:09

标签: javascript promise

我正在使用JavaScript使用内置的SubtleCrypto.digest()函数来生成密码校验和。此函数以promise对象的形式返回结果,然后将其传递给内联函数,该函数将结果转换为十六进制字节的文本表示形式。问题在于,内联文本转换功能digToHex()不会更新DOM中的隐藏字段,然后在POST请求中将其提交给服务器。

通过附加在表单按钮上的onclick()事件调用该函数。它读取用户在表单上键入的密码输入,并将其传递到digestMsg()函数以生成哈希。

请注意,我知道SHA-1周围的安全问题。目前,这仅是概念证明。

我已经在控制台和“网络”标签上观察到Chrome开发人员工具中的输出。我还监视了服务器(IOT设备)上的传入请求。提交的值始终为null。 digToHex()函数似乎正在生成哈希,因为该哈希确实会在控制台选项卡中显示为chk.value的值。从代码中可以看出,我在digestMsg() Promise处理程序的内部和外部尝试了赋值和表单提交。

function reboot() {
    var msg = document.querySelector('#pwd1').value;

    // Test purposes only
    var opt = document.querySelector('[name = "opt"]');
    var chk = document.querySelector('[name = "chk1"]');
    // Test purposes only

    digestMsg(msg).then(result=>{
        var opt = document.querySelector('[name = "opt"]');
        var chk = document.querySelector('[name = "chk1"]');
        opt.value = 3;
        chk.value = digToHex(result);
        // document.querySelector('form').submit();

    console.log(opt.value);
    console.log(chk.value);

    });
    // form.submit();

    alert("Result: " + opt.value + " - " + chk.value);
}

function digToHex(buf) {
    const bytes = new Uint8Array(buf);
    const hexCodes = [...bytes].map(value => {
        const hexCode = value.toString(16);
        const padHexCode = hexCode.padStart(2, '0');
        return padHexCode;
    });
    return hexCodes.join('');
}

function digestMsg(msg) {
    const enc = new TextEncoder();
    const data = enc.encode(msg);
    return window.crypto.subtle.digest('SHA-1', data);
}

如果未注释两行sumbit()中的任何一条,则服务器上会收到null值,但Chrome开发人员工具会在控制台输出中显示正确的值。对开发人员工具中的“网络输出”选项卡的进一步调查确认,实际上正在传输空值。我希望看到"opt"的值为3chk1的值包含哈希值。

这是调用代码的HTML:

<form method="post" action="/admin">
<input name="chk1" value="" hidden/>
<input name="chk2" value="" hidden/>
<input name="opt" value=0 hidden/>
<table>
<tr><th>Current password:</th><td><input id="pwd1" type="password">        </input></input></td>
<tr><th>New password:</th><td><input id="pwd2" type="password"></input></input></td>
<tr><th>Confirm new password:</th><td><input id="pwd3" type="password"></input></input></td>
<tr><th></th><td align="right"><input type="submit" class="btn" value="Change" onclick="change()"/></td></tr>
<tr><th></th><td><br></td></tr>
<tr><th>Defaults</th><td align="right"><input type="submit" class="btn" value="Reset" onclick="reset()"/></td></tr>
<tr><th>Restart WiFi</th><td align="right"><input type="button" class="btn" value="Reboot" onclick="reboot()"/></td></tr>
</table>
</form>

根据Marius进行的进一步测试表明,该代码确实适用于静态html页面。因此,该问题似乎与我为每个表单动态加载html的方式有关。我在下面附加了用于主页(父页面)的html:

<html>
<head>
<meta charset="utf-8">
<title>AR488 WiFi Configuration</title>
<link rel="stylesheet" href="AR488wifi.css">
<script defer src="AR488wifi.js"></script> 
</head>
<body onload="getPage('seeStat.html')";>
<div class="mpage">
<div class="headr">AR488 WiFi Configuration</div>
<div>
<ul>
<li id="mStat" class="active"><a onclick="getPage('seeStat.html')">Status</a></li>
<li id="mGen"><a onclick="getPage('cfgGen.div')">General</a></li>
<li id="mWifi"><a onclick="getPage('cfgWifi.div')">WiFi</a></li>
<li id="m488"><a onclick="getPage('cfg488.div')">GPIB</a></li>
<li id="mAdm"><a onclick="getPage('cfgAdm.div')">Admin</a></li>
</ul>
</div>
<hr>
<div id="cfgPage" class="conf">
</div>
<div>
<hr>
<table class="foot"><tr>
<td>AR488 WiFi ver: 0.00.00</td>
<td>Firmware ver: 0.00.00</td>
</tr></table>
</div>
</div>
</body>
</html>

2 个答案:

答案 0 :(得分:0)

您的代码似乎正常。我已经复制了您拥有的内容,并添加了一些HTML来模拟这一点。确保未禁用这些字段。

reboot();

function reboot() {
    var msg = document.querySelector('#pwd1').value;

    // Test purposes only
    var opt = document.querySelector('[name = "opt"]');
    var chk = document.querySelector('[name = "chk1"]');
    // Test purposes only

    digestMsg(msg).then(result=>{
        var opt = document.querySelector('[name = "opt"]');
        var chk = document.querySelector('[name = "chk1"]');
        opt.value = 3;
        chk.value = digToHex(result);

    console.log(opt.value);
    console.log(chk.value);

    });

}

function digToHex(buf) {
    const bytes = new Uint8Array(buf);
    const hexCodes = [...bytes].map(value => {
        const hexCode = value.toString(16);
        const padHexCode = hexCode.padStart(2, '0');
        return padHexCode;
    });
    return hexCodes.join('');
}

function digestMsg(msg) {
    const enc = new TextEncoder();
    const data = enc.encode(msg);
    return window.crypto.subtle.digest('SHA-1', data);
}
<input type="password" id="pwd1" value="test" />
<input type="text" name="opt" />
<input type="text" name="chk1" />

答案 1 :(得分:0)

我相信我已经找到了解决方案!

在我的原始代码中,我使用querySelector()获取对表单对象的引用,该引用立即传递给提交,但在完成 之后:

document.querySelector('form').submit();

提交表单时将“ opt”设置为“ 0”(我专门设置的数字值),而不是null或未定义,因此此命令似乎正在创建对原始未修改表单的引用,然后立即对其进行引用提交。

我进行了尝试,在处理发生之前,在digestMsg()处理程序的上下文中创建了对表单的引用:

var formObj = document.querySelector('form');

在处理完表单并更新值之后,可以使用以下方式提交表单:

formObj.submit();

这一次,表单提交了正确的更新值。调整后的代码(减去各种测试警报)现在看起来像这样:

function reboot() {
    var msg = document.querySelector('#pwd1').value;
    digestMsg(msg).then(result=>{
        var formObj = document.querySelector('form');
        var opt = document.querySelector('[name = "opt"]');
        var chk = document.querySelector('[name = "chk1"]');
        opt.value = 3;
        chk.value = digToHex(result);
        formObj.submit();
    });
}

我想知道为什么第一个命令创建了对原始修改表单的引用,而没有考虑更新后的值?在这两种情况下,事情似乎都以相同的顺序发生-将表单加载到浏览器中,更新值并提交表单。另外,为什么原始版本不能在静态HTML页面上使用但在动态加载的表单上可以使用?如果有人有解释,我会很想听听。

同时,感谢您的有用评论,这些评论帮助我集中精力思考并找到解决方案。

以上只是概念证明,需要进一步验证和调整才能获得实际的工作形式。