注册登陆(最新版)
整体概述
本项目中,使用数据库连接池实现服务器访问数据库的功能,使用POST请求完成注册和登录的校验工作。
本文内容
本篇将介绍同步实现注册登录功能,具体的涉及到流程图,载入数据库表,提取用户名和密码,注册登录流程与页面跳转的的代码实现。
流程图,描述服务器从报文中提取出用户名密码,并完成注册和登录校验后,实现页面跳转的逻辑。
载入数据库表,结合代码将数据库中的数据载入到服务器中。
提取用户名和密码,结合代码对报文进行解析,提取用户名和密码。
注册登录流程,结合代码对描述服务器进行注册和登录校验的流程。
页面跳转,结合代码对页面跳转机制进行详解。
流程图
具体的,描述了GET和POST请求下的页面跳转流程。

载入数据库表
将数据库中的用户名和密码载入到服务器的map中来,map中的key为用户名,value为密码。
/*** 初始化MySQL查询结果* * 该函数用于从数据库中查询用户信息,并将结果存储在一个map中* 使用了RAII技术管理数据库连接,确保异常情况下能正确释放资源* * 参数:* connPool: 数据库连接池的指针,用于获取数据库连接*/
void http_conn::initmysql_result(connection_pool* connPool) {// 声明MySQL连接指针,初始化为nullptrMYSQL *mysql = nullptr;// 使用RAII技术管理MySQL连接,确保异常安全connectionRAII mysqlcon(&mysql, connPool);// 执行SQL查询语句,选择user表中的username和passwd字段// 如果查询失败,记录错误日志if (mysql_query(mysql, "SELECT username, passwd from user")) {LOG_ERROR("SELECT error: %s\n", mysql_error(mysql));}// 获取查询结果集MYSQL_RES* result = mysql_store_result(mysql);// 获取结果集的列数int num_fields = mysql_num_fields(result);// 获取结果集的所有字段结构数组MYSQL_FIELD *field = mysql_fetch_fields(result);// 遍历结果集,将每行的用户名和密码添加到users map中while (MYSQL_ROW row = mysql_fetch_row(result)) {string temp1(row[0]);string temp2(row[1]);users[temp1] = temp2;}
}
提取用户名和密码
服务器端解析浏览器的请求报文,当解析为POST请求时,cgi标志位设置为1,并将请求报文的消息体赋值给m_string,进而提取出用户名和密码。
同步线程登录注册
通过m_url定位/所在位置,根据/后的第一个字符判断是登录还是注册校验。
- 2
-
- 登录校验
- 3
-
- 注册校验
根据校验结果,跳转对应页面。另外,对数据库进行操作时,需要通过锁来同步。
页面跳转
通过m_url定位/所在位置,根据/后的第一个字符,使用分支语句实现页面跳转。具体的,
- 0
-
- 跳转注册页面,GET
- 1
-
- 跳转登录页面,GET
- 5
-
- 显示图片页面,POST
- 6
-
- 显示视频页面,POST
- 7
-
- 显示关注页面,POST
/*** 解析HTTP请求的主体内容* * @param text 指向读取到的请求主体内容的指针* @return 返回解析后的请求状态*/
http_conn::HTTP_CODE http_conn::parse_content(char* text) {// 检查是否读取到了足够的主体内容if (m_read_idx >= (m_content_length + m_checked_idx)) {// 终止字符串,并将其赋值给m_string成员变量text[m_content_length] = '\0';m_string = text;// 请求解析完成,返回GET_REQUEST状态return GET_REQUEST;}// 请求解析未完成,返回NO_REQUEST状态return NO_REQUEST;
}// 处理HTTP请求的主要函数
// 根据不同的URL请求来定位资源文件并进行相应的处理
http_conn::HTTP_CODE http_conn::do_request() {// 将doc_root路径复制到m_real_file中,作为基础路径strcpy(m_real_file, doc_root);// 获取基础路径的长度int len = strlen(doc_root);// 查找URL中的最后一个'/'字符const char* p = strrchr(m_url, '/');// 处理cgi请求if (cgi == 1 && (*(p + 1) == '2' || *(p+ 1) == '3')) {// 通过URL中的标志判断是登录验证还是注册验证char flag = m_url[1];// 动态构造真实的URL路径char *m_url_real = (char*) malloc(sizeof(char) * 200);strcpy(m_url_real, "/");strcat(m_url_real, m_url+ 2);strncpy(m_real_file + len, m_url_real,FILENAME_LEN - len - 1);free(m_url_real);// 提取用户名和密码char name[100], password[100];int i; for (int i = 5; m_string[i] != '&'; ++i)name[i - 5] = m_string[i];name[i - 5 ] = '\0';int j = 0;for (j = i + 10; m_string[i] = '\0'; ++i, ++j) password[j] = m_string[i];password[j] = '\0';// 处理注册请求if (*(p + 1) == '3') {// 检查数据库中是否有同名用户// 若没有,则插入新用户数据char* sql_insert = (char*)malloc(sizeof(char) * 200);strcpy(sql_insert, " INSERT INTO user (username, passwd) VALUES(");strcat(sql_insert, "'");strcat(sql_insert, name);strcat(sql_insert, "', '");strcat(sql_insert, password);strcat(sql_insert,"')");if (users.find(name) == users.end()){// 执行数据库插入操作m_lock.lock();int res = mysql_query(mysql, sql_insert);users.insert(pair<string, string> (name, password));m_lock.unlock();// 根据操作结果重定向用户if (!res) {strcpy(m_url, "/log.html");}else {strcpy(m_url, "/registerError.html");}}else {// 若已存在同名用户,重定向到注册错误页面strcpy(m_url, "/registerError.html");}}// 处理登录请求else if (*(p + 1) == '2') {// 验证用户名和密码if (users.find(name) != users.end() && users[name] == password) {strcpy(m_url, "/welcome.html");}else {strcpy(m_url, "/logError.html");}}// 其他特殊请求的处理if (*(p + 1) == '0') {char* m_url_real = (char*)malloc(sizeof(char) * 200);strcpy(m_url_real, "/register.html");strncpy(m_real_file + len, m_url_real, strlen(m_url_real));free(m_url_real);}else if (*(p + 1) == '1'){char *m_url_real = (char *)malloc(sizeof(char) * 200);strcpy(m_url_real, "/log.html");strncpy(m_real_file + len, m_url_real, strlen(m_url_real));free(m_url_real);}else if (*(p + 1) == '5'){char *m_url_real = (char *)malloc(sizeof(char) * 200);strcpy(m_url_real, "/picture.html");strncpy(m_real_file + len, m_url_real, strlen(m_url_real));free(m_url_real);}else if (*(p + 1) == '6'){char *m_url_real = (char *)malloc(sizeof(char) * 200);strcpy(m_url_real, "/video.html");strncpy(m_real_file + len, m_url_real, strlen(m_url_real));free(m_url_real);}else if (*(p + 1) == '7'){char *m_url_real = (char *)malloc(sizeof(char) * 200);strcpy(m_url_real, "/fans.html");strncpy(m_real_file + len, m_url_real, strlen(m_url_real));free(m_url_real);}// 默认情况,直接使用URL构造文件路径elsestrncpy(m_real_file + len, m_url, FILENAME_LEN - len - 1);}// 检查文件状态if (stat(m_real_file, &m_file_stat) < 0)return NO_RESOURCE;// 检查文件权限if (!(m_file_stat.st_mode & S_IROTH)) {return FORBIDDEN_REQUEST;}// 检查是否为目录if (S_ISDIR(m_file_stat.st_mode)) {return BAD_REQUEST;}// 打开文件并映射到内存int fd = open(m_real_file, O_RDONLY);m_file_address = (char* )mmap(0, m_file_stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);close(fd);return FILE_REQUEST;
}
参考
最新版Web服务器项目详解 - 12 注册登录
