Drogon简易认证机制中execSqlAsync函数模板错误求助
问题
基于Drogon框架实现简易认证机制,采用凯撒密码加密,但所有execSqlAsync调用都出现模板错误,错误信息如下:
In template: invalid operands to binary expression ('std::stringstream' (aka 'basic_stringstream<char>') and 'std::exception') error occurred here in instantiation of function template specialization 'drogon::orm::Field::as<std::exception>' requested here in instantiation of function template specialization 'drogon::orm::internal::CallbackHolder<(lambda at /Users/<br> 41:13)>::makeValue<std::exception>' requested here in instantiation of function template specialization 'drogon::orm::internal::CallbackHolder<(lambda at /Users/<br> 41:13)>::run<1UL>' requested here in instantiation of function template specialization 'drogon::orm::internal::CallbackHolder<(lambda at <br> 41:13)>::run<true>' requested here in instantiation of member function 'drogon::orm::internal::CallbackHolder<(lambda at /Users/<br> 41:13)>::execCallback' requested here in instantiation of function template specialization 'drogon::orm::internal::CallbackHolder<(lambda at /Users/<br> 41:13)>::CallbackHolder<(lambda at patr... in instantiation of function template specialization 'drogon::orm::internal::SqlBinder::operator>> <(lambda at <br> server/AuthController.cpp:41:13), drogon::orm::internal::FunctionTraits<(lambda at /U... in instantiation of function template specialization 'drogon::orm::DbClient::execSqlAsync<(lambda at <br> server/AuthController.cpp:35:13), (lambda at /<br> server/A... candidate template ignored: deduced conflicting types for parameter '_CharT' ('char' vs. 'std::exception') candidate template ignored: could not match 'uniform_int_distribution<_IT>' against 'std::exception' candidate template ignored: could not match '_CharT[_Np]' against 'std::exception' candidate template ignored: could not match 'unsigned char[_Np]' against 'std::exception' candidate template ignored: could not match 'signed char[_Np]' against 'std::exception' candidate template ignored: could not match 'basic_string<_CharT, _Traits, _Allocator>' against 'std::exception' candidate template ignored: could not match 'bitset<_Size>' against 'std::exception' candidate template ignored: requirement 'integral_constant<bool, false>::value' was not satisfied [with _Stream = std::stringstream &, _Tp = std::exception &] candidate template ignored: could not match '__iom_t7<_MoneyT>' against 'std::exception' candidate template ignored: could not match '__iom_t9<_CharT>' against 'std::exception'
对应的实现代码:
#include "AuthController.h" #include <drogon/drogon.h> #include <drogon/orm/DbClient.h> #include <algorithm> using namespace drogon; using namespace drogon::orm; // Simple Caesar Cipher function std::string caesarCipher(const std::string& text, int shift) { std::string result = text; std::transform(result.begin(), result.end(), result.begin(), [shift](char c) -> char { if (c >= 'a' && c <= 'z') return 'a' + (c - 'a' + shift) % 26; else if (c >= 'A' && c <= 'Z') return 'A' + (c - 'A' + shift) % 26; else return c; }); return result; } void AuthController::signup(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback) { auto json = req->getJsonObject(); std::string username = json->get("username", "").asString(); std::string password = json->get("password", "").asString(); // Encrypt the password using Caesar cipher std::string encryptedPassword = caesarCipher(password, 3); auto client = drogon::app().getDbClient().get(); client->execSqlAsync( "INSERT INTO users (username, password_hash) VALUES ($1, $2)", [callback](const Result &result) { auto response = HttpResponse::newHttpResponse(); response->setStatusCode(HttpStatusCode::k200OK); response->setBody("Signup successful"); callback(response); }, [callback](const std::exception &e) { // Correct exception handling auto response = HttpResponse::newHttpResponse(); response->setStatusCode(HttpStatusCode::k500InternalServerError); response->setBody(e.what()); callback(response); }, username, encryptedPassword); } void AuthController::login(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback) { auto json = req->getJsonObject(); std::string username = json->get("username", "").asString(); std::string password = json->get("password", "").asString(); auto client = drogon::app().getDbClient(); client.get()->execSqlAsync( "SELECT password_hash FROM users WHERE username = $1", [password, callback](const Result &result) { std::shared_ptr<HttpResponse> response; if (!result.empty()) { std::string storedHash = result[0]["password_hash"].as<std::string>(); std::string decryptedPassword = caesarCipher(storedHash, -3); if (decryptedPassword == password) { response = HttpResponse::newHttpResponse(); response->setStatusCode(k200OK); response->setBody("Login successful"); } else { response = HttpResponse::newHttpResponse(); response->setStatusCode(k401Unauthorized); response->setBody("Login failed"); } } else { response = HttpResponse::newHttpResponse(); response->setStatusCode(k401Unauthorized); response->setBody("User not found"); } callback(response); }, [callback](const std::exception &e) { auto resp = HttpResponse::newHttpResponse(); resp->setStatusCode(k500InternalServerError); resp->setBody(e.what()); callback(resp); }, username); }
分析与解决
问题原因
Drogon的execSqlAsync函数对错误回调的参数类型有严格要求:它需要接收const DrogonDbException&而非const std::exception&。代码中错误地使用了std::exception,导致模板推导时把它当成了要从数据库字段解析的类型,进而尝试用std::stringstream转换std::exception,触发类型不匹配的错误。
修复步骤
- 将两个
execSqlAsync调用中的错误回调参数类型从const std::exception &e改为const DrogonDbException &e。 - 添加
DrogonDbException对应的头文件:#include <drogon/orm/DrogonDbException.h>。
修复后的代码
#include "AuthController.h" #include <drogon/drogon.h> #include <drogon/orm/DbClient.h> #include <drogon/orm/DrogonDbException.h> // 添加该头文件 #include <algorithm> using namespace drogon; using namespace drogon::orm; // Simple Caesar Cipher function std::string caesarCipher(const std::string& text, int shift) { std::string result = text; std::transform(result.begin(), result.end(), result.begin(), [shift](char c) -> char { if (c >= 'a' && c <= 'z') return 'a' + (c - 'a' + shift) % 26; else if (c >= 'A' && c <= 'Z') return 'A' + (c - 'A' + shift) % 26; else return c; }); return result; } void AuthController::signup(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback) { auto json = req->getJsonObject(); std::string username = json->get("username", "").asString(); std::string password = json->get("password", "").asString(); // Encrypt the password using Caesar cipher std::string encryptedPassword = caesarCipher(password, 3); auto client = drogon::app().getDbClient().get(); client->execSqlAsync( "INSERT INTO users (username, password_hash) VALUES ($1, $2)", [callback](const Result &result) { auto response = HttpResponse::newHttpResponse(); response->setStatusCode(HttpStatusCode::k200OK); response->setBody("Signup successful"); callback(response); }, // 修改错误回调参数类型 [callback](const DrogonDbException &e) { auto response = HttpResponse::newHttpResponse(); response->setStatusCode(HttpStatusCode::k500InternalServerError); response->setBody(e.what()); callback(response); }, username, encryptedPassword); } void AuthController::login(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback) { auto json = req->getJsonObject(); std::string username = json->get("username", "").asString(); std::string password = json->get("password", "").asString(); auto client = drogon::app().getDbClient(); client.get()->execSqlAsync( "SELECT password_hash FROM users WHERE username = $1", [password, callback](const Result &result) { std::shared_ptr<HttpResponse> response; if (!result.empty()) { std::string storedHash = result[0]["password_hash"].as<std::string>(); std::string decryptedPassword = caesarCipher(storedHash, -3); if (decryptedPassword == password) { response = HttpResponse::newHttpResponse(); response->setStatusCode(k200OK); response->setBody("Login successful"); } else { response = HttpResponse::newHttpResponse(); response->setStatusCode(k401Unauthorized); response->setBody("Login failed"); } } else { response = HttpResponse::newHttpResponse(); response->setStatusCode(k401Unauthorized); response->setBody("User not found"); } callback(response); }, // 修改错误回调参数类型 [callback](const DrogonDbException &e) { auto resp = HttpResponse::newHttpResponse(); resp->setStatusCode(k500InternalServerError); resp->setBody(e.what()); callback(resp); }, username); }
内容的提问来源于stack exchange,提问作者yagil
相关产品推荐
相关产品推荐

