为了账号安全,请及时绑定邮箱和手机立即绑定

函数运行后数组为空?

函数运行后数组为空?

UYOU 2023-04-27 16:14:10
app.post('/api/edit-profile', regularFunctions, async function (req, res) {    let email = req.body.email    let password_current = req.body.password_current    connection.query('SELECT * FROM accounts WHERE id = ?', req.body.id, async function (err, results) {        if (results.length > 0) {            bcrypt.compare(password_current, results[0].password, async function (err, isMatch) {                if (err) {                    res.send('Unable to save settings')                    res.end();                    throw err                } else if (!isMatch) {                    res.send('Password doesn\'t match.')                    res.end();                } else {                    let changed = []                    // Password matches                    if (req.body.password_new) {                        let newPassword = req.body.password_new                        let hashed_password = await hashPassword(newPassword)                        connection.query('UPDATE accounts SET password = ? WHERE id = ?', [hashed_password, req.body.id], async function (error, results) {                            if (results.affectedRows && results.affectedRows > 0) {                                changed.push('password')                            } else {                                res.send('Unable to save settings')                                res.end();                            }                        })                    }我知道这对一些专家编码员来说似乎是一个非常简单的问题,但我对整个异步和同步的事情有点陌生。为什么“已更改”数组即使在函数运行后被推送到也不会更新?我想做的是让它只返回一个可以在客户端显示的字符串,但它似乎并没有改变它,只返回“成功改变,”
查看完整描述

2 回答

?
德玛西亚99

TA贡献1770条经验 获得超3个赞

这个功能让我感到困惑,因为它有很多责任,但我发现了问题:

connection.query方法是非阻塞的,这意味着它不会等待它的执行结束以前进到下一条指令。

当您使用异步方法和时Promise,最好尝试保持方法的一致性(避免混合回调函数和asyncawait)。async如果使用/ ,我已经重构了它应该是什么样子await

app.post('/api/edit-profile', regularFunctions, async function (req, res) {

    let email = req.body.email

    let password_current = req.body.password_current

    let results = await executeQuery(connection, 'SELECT * FROM accounts WHERE id = ?', [req.body.id]);

    if (results.length > 0) {

        let isMatch = await comparePassword(password_current, results[0].password);

        if (!isMatch) {

            throw new Error(`Password doesn't match`);

        }

        let changed = []

        // Password matches

        if (req.body.password_new) {

            let newPassword = req.body.password_new

            let hashed_password = await hashPassword(newPassword)

            let results = await executeQuery(connection, 'UPDATE accounts SET password = ? WHERE id = ?', [hashed_password, req.body.id]);

            if (results.affectedRows && results.affectedRows > 0) {

                changed.push('password')

            } else {

                throw new Error('Unable to save settings');

            }

        }

        if (req.body.license_key) {

            let newKey = req.body.license_key

            let response = await axios.get(`https://voltcloud.net/api/hosting/check-key/${newKey}`, {

                headers: {

                    authorization: '<redacted>'

                }

            });

            let data = response.data

            if (typeof data === 'object') {

                if (data.active === 1) {

                    let response = await axios({

                        method: 'post',

                        url: `https://voltcloud.net/api/hosting/activate-key/${newKey}`,

                        headers: {

                            authorization: '<redacted>'

                        }

                    })

                    if (response.data === 'Success') {

                        let results = await executeQuery(connection, 'UPDATE accounts SET license_key = ? WHERE id = ?', [newKey, req.body.id]);

                        if (results.affectedRows && results.affectedRows > 0) {

                            changed.push('license key')

                        } else {

                            throw new Error('Unable to save settings');

                        }

                    } else if (data === 'License already active!') {

                        throw new Error('License key is already active!');

                    } else if (data === 'Failed to update key.') {

                        throw new Error('Unable to save settings');

                    } else {

                        throw new Error('Unable to save settings');

                    }

                }

            }

        }

        let results = await executeQuery(connection, 'UPDATE accounts SET email = ? WHERE id = ?', [email,req.body.id]);

        if (results.affectedRows && results.affectedRows > 0) {

            changed.push('email')

        } else {

            throw new Error('Unable to save settings');

        }

        let finalTxt = 'Successfully changed, '

        if (changed.length > 1) {

            changed.forEach(function (txt, index) {

                if (index === 0) {

                    finalTxt = finalTxt + txt

                } else if (index === 2) {

                    finalTxt = finalTxt + `and ${txt}.`

                }

            })

        } else if (changed.length === 1) {

            finalTxt = `Successfully changed ${changed[0]}.`

        }

        res.send(finalTxt)

        res.end();

    }

});


function executeQuery(conn, sql, params) {

    return new Promise((resolve, reject) => {

        conn.query(sql, params, function (err, data) {

            if (err != null) {

                return reject(err);

            }

            return resolve(data);

        });

    });

}


function comparePassword(val1, val2) {

    return new Promise((resolve, reject) => {

        bcrypt.compare(val1, val2, function (err, isMatch) {

            if (err != null) {

                return reject(err);

            }

            resolve(isMatch);

        });

    })

}

请注意,我们根本没有使用回调函数,即使在我们没有基于本机的Promise函数(即 mysql 连接)的情况下,我们也委托给一个函数来代理回调以提供Promise并保持最终的一致性执行。


查看完整回答
反对 回复 2023-04-27
?
喵喵时光机

TA贡献1846条经验 获得超7个赞

if原始代码在发送响应之前并没有等待两个分支完成。由于嵌套,很难在回调中构造这样的代码。

尽可能使用async函数await。它允许更多的可读代码和更容易的错误处理。所以这个答案更多的是代码审查,而不是针对您的问题的简单修复。

拆分出一些在其他路由中有用的通用帮助代码:

// Generate errors for the web, with context

function responseError(message, status, data){

    const error = new Error(message)

    error.status = status

    for (const key in data){

        error[key] = data[key]

    }

    return error

}


// Turn mysql callbacks into promises (or use util.promisify)

async function runQuery(query, values){

    return new Promise((resolve, reject) => {

        connection.query(query, values, function(error, results){

            if (error) return reject(error)

            return resolve(results)

        })

    })

}


async function runUpdateQuery(query, values){

    const results = await runQuery(query, values)

    if (!results) throw responseError('No update result', 500, { query })

    if (!results.affectedRows) throw responseError('No affected rows', 400, { query })

    return results

}

来自两个条件的代码if可以很容易地分开,以及其他帐户操作。


async function apiAuthUserId(id, password){

    const results = await runQuery('SELECT * FROM accounts WHERE id = ?', id)

    if (!results.length) throw responseError('No account', 400, { id })

    const isMatch = await bcrypt.compare(password_current, results[0].password)

    if (!isMatch) throw responseError('Password doesn\'t match', 400)

    return true

}


async function apiUpdatePassword(id, password){

    let newPassword = req.body.password_new

    let hashed_password = await hashPassword(newPassword)

    await runUpdateQuery('UPDATE accounts SET password = ? WHERE id = ?', [hashed_password, req.body.id])

    return id

}


async function apiUpdateEmail(id, email){

    await runUpdateQuery('UPDATE accounts SET email = ? WHERE id = ?', [email, id])

    return email

}


async function apiUpdateLicenseKey(id, licenseKey){

    const response_license = await axios.get(`https://voltcloud.net/api/hosting/check-key/${licenseKey}`, {

        headers: {

            authorization: 'somekey'

        }

    })


    const data = response_license.data

    if (!data) {

      throw responseError('No license key response data', 500, { response: response_license })

    }

    if (data.active !== 1) {

      throw responseError('License key not active', 400,  { key: licenseKey })

    }

    const response_activate = await axios({

        method: 'post',

        url: `https://voltcloud.net/api/hosting/activate-key/${licenseKey}`,

        headers: {

            authorization: 'somekey'

        }

    })


    switch (response_activate.data){

        case 'License already active!':

            throw responseError('License key is already active!', 400, { response: response_activate })

        case 'Failed to update key.':

            throw responseError('Unable to save settings!', 400, { response: response_activate })

        case 'Success':

            await runUpdateQuery('UPDATE accounts SET license_key = ? WHERE id = ?', [licenseKey, req.body.id])

            return licenseKey

        default:

            throw responseError('Unable to save settings!', 500, { response: response_activate })

    }

}

这样您的路由代码就可以更简洁一些,并显示需要完成的工作,而不是如何完成所有工作。


app.post('/api/edit-profile', regularFunctions, async function (req, res) {

    const changed = []

    try {

        const { id, email, password_current } = req.body


        await apiAuthUserId(id, password_current)


        // Password matches

        if (req.body.password_new) {

            await apiUpdatePassword(id, req.body.password_new)

            changed.push('password')

        }


        // License key

        if (req.body.license_key) {

            await apiUpdateLicenseKey(id, req.body.license_key)

            changed.push('license key')

        }


        await apiUpdateEmail(id, email)

        changed.push('email')


        let finalTxt = `Successfully changed ${changed.join(' and ')}.`

        res.send(finalTxt)

    }

    catch (error) {

        // If your not using transactions, might need to deal with partial `changed` responses here. 

        console.error('Error /api/edit-profile', error)

        res.status(error.status||500).send(`Error: ${error.message}`)

    }

});


查看完整回答
反对 回复 2023-04-27
  • 2 回答
  • 0 关注
  • 104 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信