绑定事件导致--类方法的return返回后再次执行,一共执行两次的错误

一、问题

今天,出现了JSP页面请求Controller层方法,方法返回后自动再次执行第二遍的问题。

二、调试过程

1、后台逻辑有误?

用IDE的调试程序检测了一遍,发现每次正常返回web容器后,会再回头调一遍本方法;最初以为是后台逻辑的问题,但本方法内容比较简单,没有复杂的代码逻辑,所以排除了后台方法逻辑错误的因素;

2、页面请求了两次?

使用Chorme浏览器,在页面打断点测试页面请求是不是请求了两次,经过测试发现,页面只发生一次请求,排除页面重复提交的因素。

3、页面JS有误?事件重复?

查了一遍JS代码,并没有发现重复事件或者id重复发生。排除JS代码的因素;之前有一个同事遇到过同样的问题,原因是JSP的页面头一个meta开头的引用重复,参数冲突。

三、错误原因

排查过程中发现页面中有使用以下方式的按钮绑定事件

$("#advancepay_button").on('click', function() {
$("#advancepay_button").attr("disabled",true);
});

四、处理

只需要在使用过绑定事件调用方法成功之后增加解绑定动作就可以了。具体语句如下:

$("#submit_button").unbind('click');

找出错误:string generate_random_string() { srand(time(nullptr)); int length = rand() % 5 + 1; const string charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; string result; for (int i = 0; i < length; ++i) { result += charset[rand() % charset.size()]; } return result; } string xor_encrypt(const string& plaintext, const string& key) { string ciphertext; for(size_t i = 0; i < plaintext.size(); ++i) { ciphertext += plaintext[i] ^ key[i % key.size()]; } return ciphertext; }void saveCredentials(const string& username, const string& password) { const string ran = generate_random_string(); ofstream file(CREDENTIALS_FILE); if (file.is_open()) { file << ran << xor_encrypt(username, ran) << '\n' << xor_encrypt(username, ran); file.close(); } else { throw runtime_error("无法保存凭据"); } } pair<string, string> loadCredentials() { ifstream file(CREDENTIALS_FILE); if (!file.is_open()) { throw runtime_error("无法读取凭据文件"); } string username, password, ran; getline(file, ran); getline(file, xor_encrypt(username, ran)); getline(file, xor_encrypt(username, ran)); return pair<string, string>(username, password); } bool authenticate() { string username, password; cout << "请输入用户名: "; cin >> username; cout << "请输入密码: "; cin >> password; try { pair<string, string> credentials = loadCredentials(); if (credentials.first == username && credentials.second == password) { system("cls"); return true; } else { return false; } } catch (const runtime_error&) { cout << "凭据文件不存在,已经设置新的凭据。\n"; Sleep(1000); saveCredentials(username, password); return true; } }
最新发布
03-23
<think>好的,我现在需要分析用户提供的C++代码,找出其中的错误并解释原因。首先,我会仔细阅读代码,了解各个函数的功能以及它们之间的交互。 首先看`generate_random_string`函数。这个函数用来生成一个随机字符串,长度在1到5之间。函数开头调用了`srand(time(nullptr))`,这里可能存在一个问题:每次调用这个函数都会重新设置随机数种子,如果在短时间内多次调用,可能会生成相同的随机数,因为`time(nullptr)`返回的是秒级时间。不过在这个代码中,`generate_random_string`只在`saveCredentials`中被调用一次,所以这个问题可能影响不大,但作为代码规范来说,通常建议只设置一次随机种子,比如在程序开始时。 接下来是`xor_encrypt`函数,它执行异或加密。参数是明文和密钥,循环中对每个明文字节与密钥的对应字节进行异或。这里可能的问题是没有处理密钥为空的情况,但在这个代码中,密钥是`generate_random_string`生成的,长度至少为1,所以暂时不会有问题。 然后是`saveCredentials`函数。这里将随机字符串`ran`和加密后的用户名两次写入文件。注意到这里加密用户名的密钥是`ran`,但写入文件的是`ran`本身,然后两次加密后的结果。问题可能出在保存的内容是否正确。比如,这里将`ran`写入文件的第一行,然后写入两次加密后的用户名,但可能应该保存加密后的用户名和密码。当前代码中,`file << ran << xor_encrypt(username, ran) << '\n' << xor_encrypt(username, ran);`,这里可能应该是加密密码而不是两次加密用户名。这是一个逻辑错误,因为保存的第二个字段应该是加密后的密码,但这里用了两次加密的用户名,导致密码没有被正确保存。 接下来是`loadCredentials`函数。这里尝试从文件中读取三行数据:`ran`、加密后的用户名和加密后的密码。但是,`saveCredentials`中写入的方式可能有问题。因为`file << ran << ...`这样写的话,`ran`后面直接接加密后的字符串,中间没有换行符,导致`getline(file, ran)`会读取整个第一行,包括`ran`和加密后的用户名,直到遇到换行符。但原来的写入方式是将`ran`和加密后的用户名连在一起,后面加上换行符,然后写入另一个加密后的用户名。例如,假设`ran`是"abc",加密后的用户名是"def",那么第一行的内容会是"abcdef\n",而第二行是另一个加密后的用户名。这样,当使用`getline(file, ran)`时,`ran`会被读取为整个第一行,即"abcdef",而接下来的`getline(file, ...)`会读取第二行,而第三行可能不存在,导致错误。 具体来说,`saveCredentials`中的写入操作是: `file << ran << xor_encrypt(username, ran) << '\n' << xor_encrypt(username, ran);` 这里,第一行是`ran`拼接加密后的用户名,然后换行,接着写入另一个加密后的用户名。例如,假设ran是"abc",加密后的用户名是"def",那么第一行是"abcdef",第二行是"def"(假设加密后的结果还是"def")。然后`loadCredentials`中第一行读取到`ran`变量,但实际上`ran`应该是原随机字符串,但此时`ran`被赋值为整个第一行的内容,即"abcdef",而之后用这个错误的`ran`去解密后面的内容,会导致错误。 另一个问题是,在`saveCredentials`中,应该保存加密后的密码,而不是两次加密用户名。当前代码中的第二个加密参数应该是`password`,即`xor_encrypt(password, ran)`,而不是再次加密用户名。这导致保存的密码实际上是错误的,因为使用了用户名来加密,而后续验证时无法正确解密。 在`loadCredentials`中,使用`getline(file, xor_encrypt(username, ran))`是错误的,因为`getline`的第二个参数应该是一个字符串变量,用于存储读取的内容,而这里传入的是加密后的结果。实际上,应该先读取加密后的字符串,然后用`ran`进行异或解密。例如,正确的步骤应该是:读取第一行作为`ran`,读取第二行作为加密后的用户名,读取第三行作为加密后的密码。然后,对这两个加密后的字符串用`ran`进行异或解密得到明文用户名和密码。但当前代码中,`getline`的参数是错误的,因为`xor_encrypt`返回的是一个临时字符串,无法作为参数传递给`getline`,这会导致编译错误。此外,`xor_encrypt`函数执行的是加密,而实际上在读取时应该进行解密,但异或加密和解密是同一个操作,所以这里的问题在于参数传递的方式。 例如,在`loadCredentials`中,正确的做法应该是: 1. 读取ran字符串。 2. 读取加密后的用户名密文。 3. 读取加密后的密码密文。 4. 对这两个密文用ran进行异或解密,得到明文用户名和密码。 但当前代码中,`getline(file, xor_encrypt(username, ran))`是错误的,因为`getline`需要一个可修改的字符串引用,而`xor_encrypt`返回的是一个临时对象,无法绑定到非const引用。这会导致编译错误。 此外,在`authenticate`函数中,当首次运行时,会捕获到异常,然后调用`saveCredentials(username, password)`,但此时保存的是用随机字符串加密后的用户名两次,而没有保存密码。这会导致后续加载时密码不正确。 总结错误: 1. **saveCredentials中的写入逻辑错误**:将两次加密后的用户名写入文件,而应该保存加密后的用户名和加密后的密码。 - 错误代码:`file << ran << xor_encrypt(username, ran) << '\n' << xor_encrypt(username, ran);` - 应改为:`file << ran << '\n' << xor_encrypt(username, ran) << '\n' << xor_encrypt(password, ran);` 2. **loadCredentials中的读取和解密错误**:错误地使用`getline`试图将结果直接解密,导致编译错误,并且读取顺序错误- 错误代码: ```cpp getline(file, ran); getline(file, xor_encrypt(username, ran)); getline(file, xor_encrypt(username, ran)); ``` - 应改为先读取密文,再进行解密: ```cpp string encrypted_username, encrypted_password; getline(file, ran); getline(file, encrypted_username); getline(file, encrypted_password); username = xor_encrypt(encrypted_username, ran); password = xor_encrypt(encrypted_password, ran); ``` 3. **文件写入格式问题**:在保存时,`ran`和加密后的用户名被写在同一行,导致读取时`ran`包含多余的内容。 - 例如,`file << ran << xor_encrypt(...)`会导致ran和加密后的字符串合并,读取时`ran`变量将包含整个字符串,而后续解密无法正确进行。 - 应该将`ran`单独作为一行写入,然后写入加密后的用户名和密码各占一行。 4. **异或加密后的二进制数据可能包含不可打印字符**,当使用`ofstream`的文本模式写入时,可能导致数据损坏。例如,如果加密后的字符包含'\n',则会被视为换行符,破坏文件结构。应该以二进制模式处理,或者将加密后的数据进行编码(如Base64)后再保存。 5. **在loadCredentials中,读取的三行数据可能不正确**,因为保存时可能没有正确分隔行。例如,原代码中`file << ran << ...`可能导致ran和加密后的字符串在同一行,导致读取错误。 其他问题可能包括: - `generate_random_string`生成的随机字符串长度可能过短(1-5字节),导致密钥不够安全。 - 没有处理文件读取时的错误,比如文件内容不足三行。 - 在`authenticate`函数中,当保存新凭据后,直接返回true,但此时并未验证用户输入的凭据是否正确,而是直接信任第一次输入的用户名和密码,这可能不符合安全要求。 现在需要将这些错误逐一指出,并提供修正后的代码。</think>以下是代码中的关键错误及修正方案: 1. **文件格式错误** ```cpp // 错误写法:ran和加密数据混在同一行 file << ran << xor_encrypt(username, ran) << ... // 正确写法:每个数据独立一行 file << ran << '\n' << xor_encrypt(username, ran) << '\n' << xor_encrypt(password, ran); ``` 2. **错误的解密逻辑** ```cpp // 错误写法:直接解密到目标变量 getline(file, xor_encrypt(username, ran)); // 正确写法:先读取密文再解密 string encrypted_user, encrypted_pass; getline(file, ran); getline(file, encrypted_user); getline(file, encrypted_pass); username = xor_encrypt(encrypted_user, ran); password = xor_encrypt(encrypted_pass, ran); ``` 3. **密码保存错误** ```cpp // 错误两次保存加密的用户名 file << xor_encrypt(username, ran); // 正确:应分别保存用户名和密码的加密结果 file << xor_encrypt(username, ran) << '\n' << xor_encrypt(password, ran); ``` 完整修正代码: ```cpp // 生成随机字符串(增加长度) string generate_random_string() { static bool seeded = false; if (!seeded) { srand(time(nullptr)); seeded = true; } const int length = 16; // 更安全的长度 const string charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; string result; for (int i = 0; i < length; ++i) { result += charset[rand() % charset.size()]; } return result; } // 保持不变 string xor_encrypt(const string& plaintext, const string& key) { string ciphertext; for(size_t i = 0; i < plaintext.size(); ++i) { ciphertext += plaintext[i] ^ key[i % key.size()]; } return ciphertext; } // 修正保存逻辑 void saveCredentials(const string& username, const string& password) { const string ran = generate_random_string(); ofstream file(CREDENTIALS_FILE); if (file.is_open()) { file << ran << '\n' << xor_encrypt(username, ran) << '\n' << xor_encrypt(password, ran); file.close(); } else { throw runtime_error("无法保存凭据"); } } // 修正读取逻辑 pair<string, string> loadCredentials() { ifstream file(CREDENTIALS_FILE); if (!file.is_open()) { throw runtime_error("无法读取凭据文件"); } string ran, encrypted_user, encrypted_pass; getline(file, ran); getline(file, encrypted_user); getline(file, encrypted_pass); return {xor_encrypt(encrypted_user, ran), xor_encrypt(encrypted_pass, ran)}; } // 保持认证逻辑不变 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值