WebServer -- 注册登录
目录
🍉整体内容
🌼流程图
🎂载入数据库表
提取用户名和密码
🚩同步线程登录注册
补充解释
代码
😘页面跳转
补充解释
代码
🍉整体内容
概述
TinyWebServer 中,使用数据库连接池实现服务器访问数据库的功能,使用 POST请求 完成 注册和登录的校验工作
内容
本博客介绍同步实现注册登录功能,具体涉及:流程图,载入数据库表,提取用户名和密码,注册登录流程,以及页面跳转的代码实现
- 流程图
服务器从报文中提取用户名密码,接着,完成注册登录校验后,实现页面跳转逻辑- 载入数据库表
将数据库的数据载入服务器- 提取用户名和密码
解析报文,提取用户名和密码- 注册登录流程
描述服务器注册和登录校验的流程- 页面跳转
详解页面跳转机制
🌼流程图
具体地,描述了 GET 和 POST 请求下的页面跳转流程👇
🎂载入数据库表
将数据库的用户名和密码,载入服务器的 map 中,map中,key是用户名,value是密码
// 用户名和密码
map<string, string> users;void http_conn::initmysql_result(connection_pool *connPool)
{// 先从连接池取一个连接MYSQL *mysql = NULL;connectionRAII mysqlcon(&mysql, connPool); // 利用connectionRAII封装的RAII机制获取数据库连接// 在 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 *fields = mysql_fetch_fields(result); // 获取结果集中所有字段的信息// 从结果集获取下一行,将对应用户名和密码,存入 mapwhile (MYSQL_ROW row = mysql_fetch_row(result)) // 迭代每一行数据{string temp1(row[0]); // 提取用户名string temp2(row[1]); // 提取密码users[temp1] = temp2; // 将用户名和密码存入map中}
}
提取用户名和密码
服务器解析浏览器的请求报文,当解析为POST请求时,cgi 标志位设置为1,并将请求报文的消息体赋值给 m_string,进而提取出用户名和密码
// 用户名和密码
map<string, string> users;void http_conn::initmysql_result(connection_pool *connPool)
{// 先从连接池取一个连接MYSQL *mysql = NULL;connectionRAII mysqlcon(&mysql, connPool); // 利用connectionRAII封装的RAII机制获取数据库连接// 在 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 *fields = mysql_fetch_fields(result); // 获取结果集中所有字段的信息// 从结果集获取下一行,将对应用户名和密码,存入 mapwhile (MYSQL_ROW row = mysql_fetch_row(result)) // 迭代每一行数据{string temp1(row[0]); // 提取用户名string temp2(row[1]); // 提取密码users[temp1] = temp2; // 将用户名和密码存入map中}
}
🚩同步线程登录注册
通过 m_url 定位 / 所在位置,根据 / 后第一个字符,判断是登录还是注册校验
- 2
- 登录校验
- 3
- 注册校验
根据校验结果,跳转对应页面;此外,对数据库操作时,需要通过锁来同步
补充解释
首先通过解析URL判断用户是要进行注册还是登录操作,这是通过检查URL中的下一个字符来实现的
如果是注册操作,首先会检查数据库中是否已经存在相同的用户名,如果不存在则向数据库中插入新的用户名和密码,并在map中记录该用户的信息
如果是登录操作,会直接在map中查找用户输入的用户名和密码,如果存在且匹配,则返回欢迎页面,否则返回登录错误页面
无论是注册还是登录,操作完成后都会修改URL,将用户重定向到相应的页面,以提供反馈给用户
std::strrchr - cppreference.com
👆返回字符串中,最后一次出现该字符的位置
std::strcpy - cppreference.com
👆strcpy(dest, src) src 复制到 dest
std::strcat - cppreference.com
👆strcat(dest, src) src 追加到 dest 后
代码
const char *p = strrchr(m_url, '/'); // 在字符串 m_url 中查找最后一次出现字符 '/' 的位置,并返回指向该位置的指针if (0 == m_SQLVerify) {if (*(p + 1) == '3') // 如果 URL 中的下一个字符是 '3'{// 如果是注册,先检测数据库中是否有重名// 没有重名,就增加数据char *sql_insert = (char *)malloc(sizeof(char) * 200); // 分配内存空间strcpy(sql_insert, "INSERT INTO user(username, passwd) VALUES("); // 拼接SQL语句strcat(sql_insert, "'"); // 拼接SQL语句strcat(sql_insert, name); // 拼接SQL语句strcat(sql_insert, "', '"); // 拼接SQL语句strcat(sql_insert, "password"); // 拼接SQL语句strcat(sql_insert, "')"); // 拼接SQL语句// 判断 map 中能否找到重复的用户名if (user.find(name) == users.end()) { // 如果在map中找不到重复的用户名// 向数据库插入数据时,需要通过锁来同步数据m_lock.lock(); // 加锁int res = mysql_query(mysql, sql_insert); // 执行SQL语句users.insert(pair<string, string>(name, password)); // 将用户名和密码插入map中m_lock.unlock(); // 解锁// 校验成功,跳转登录页面if (!res)strcpy(m_url, "/log.html"); // 修改URL,跳转至登录页面// 校验失败,跳转注册失败页面else strcpy(m_url, "/registerError.html"); // 修改URL,跳转至注册失败页面}else strcpy(m_url, "/registerError.html"); // 修改URL,跳转至注册失败页面}// 如果是登录,直接判断// 若浏览器输入的用户名和密码在表中可以查找到,返回 1,否则返回 0else if (*(p + 1) == '2') { // 如果 URL 中的下一个字符是 '2'if (users.find(name) != users.end() && users[name]) // 如果在map中找到用户名,并且密码正确strcpy(m_url, "/welcome.html"); // 修改URL,跳转至欢迎页面elsestrcpy(m_url, "/logError.html"); // 修改URL,跳转至登录错误页面}
}
😘页面跳转
通过 m_url 定位 / 所在位置,根据 / 后的第一个字符,使用分支语句实现页面跳转,具体👇
- 0
- 跳转注册页面,GET
- 1
- 跳转登录页面,GET
- 5
- 显示图片页面,POST
- 6
- 显示视频页面,POST
- 7
- 显示关注页面,POST
补充解释
malloc - cppreference.com
1)👆动态分配内存
#include <stdio.h>
#include <stdlib.h>int main(void)
{int *p1 = malloc(4*sizeof(int)); // 分配足够空间以存储一个包含 4 个整数的数组int *p2 = malloc(sizeof(int[4])); // 同上,直接命名类型int *p3 = malloc(4*sizeof *p3); // 同上,无需重复类型名称if(p1) {for(int n=0; n<4; ++n) // 填充数组p1[n] = n*n;for(int n=0; n<4; ++n) // 打印数组内容printf("p1[%d] == %d\n", n, p1[n]);}free(p1); // 释放动态分配的内存free(p2);free(p3);
}
std::strncpy - cppreference.com
2)👆char *strncpy(char *dest, const char *src, size_t n)
src 复制到 dest,最多赋值 n 个字符,如果 src 长度 < n,dest 剩余部分空字节 \0 填充
eg:
#include <cstring>
#include <iostream>int main()
{const char* src = "hi";char dest[6] = {'a', 'b', 'c', 'd', 'e', 'f'};std::strncpy(dest, src, 5);std::cout << "The contents of dest are: ";for (char c : dest){if (c)std::cout << c << ' ';elsestd::cout << "\\0" << ' ';}std::cout << '\n';
}
前 5 个字符被替换为 h i \0 \0 \0,第 6 个字符保留原来的 f
The contents of dest are: h i \0 \0 \0 f
代码
// 找到 url 中 / 所在位置,进而判断 / 后第一个字符
const char *p = strrchr(m_url, '/');// 注册页面
if (*(p + 1) == '0') {// 分配内存以存储 URL 字符串,使用类型转换将返回的指针转换为 char 类型指针char *m_url_real = (char *)malloc(sizeof(char) * 200);strcpy(m_url_real, "/register.html");// 将注册页面的 URL 复制到实际文件路径中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");// 将登录页面的 URL 复制到实际文件路径中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");// 将图片页面的 URL 复制到实际文件路径中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, "/vedio.html");// 将视频页面的 URL 复制到实际文件路径中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");// 将关注页面的 URL 复制到实际文件路径中strncpy(m_real_file + len, m_url_real, strlen(m_url_real));// 释放内存free(m_url_real);
}// 否则发送 url 实际请求的文件
else// 将原始 URL 复制到实际文件路径中strncpy(m_real_file + len, m_url, FILENAME_LEN - len - 1);
相关文章:
WebServer -- 注册登录
目录 🍉整体内容 🌼流程图 🎂载入数据库表 提取用户名和密码 🚩同步线程登录注册 补充解释 代码 😘页面跳转 补充解释 代码 🍉整体内容 概述 TinyWebServer 中,使用数据库连接池实现…...
C3_W2_Collaborative_RecSys_Assignment_吴恩达_中英_Pytorch
Practice lab: Collaborative Filtering Recommender Systems(实践实验室:协同过滤推荐系统) In this exercise, you will implement collaborative filtering to build a recommender system for movies. 在本次实验中,你将实现协同过滤来构建一个电影推荐系统。 …...
Elasticsearch使用function_score查询酒店和排序
需求 基于用户地理位置,对酒店做简单的排序,非个性化的推荐。酒店评分包含以下: 酒店类型(依赖用户历史订单数据):希望匹配出更加符合用户使用的酒店类型酒店评分:评分高的酒店用户体验感好ge…...
iOS消息发送流程
Objc的方法调用基于消息发送机制。即Objc中的方法调用,在底层实际都是通过调用objc_msgSend方法向对象消息发送消息来实现的。在iOS中, 实例对象的方法主要存储在类的方法列表中,类方法则是主要存储在原类中。 向对象发送消息,核心…...
【接口测试】常见HTTP面试题
目录 HTTP GET 和 POST 的区别 GET 和 POST 方法都是安全和幂等的吗 接口幂等实现方式 说说 post 请求的几种参数格式是什么样的? HTTP特性 HTTP(1.1) 的优点有哪些? HTTP(1.1) 的缺点有哪些&#x…...
服务器硬件基础知识
1. 服务器分类 服务器分类 服务器的分类没有一个统一的标准。 从多个多个维度来看服务器的分类可以加深我们对各种服务器的认识。 N.B. CISC: complex instruction set computing 复杂指令集计算 RISC: reduced instruction set computer 精简指令集计算 EPIC: explicitly p…...
matlab实现层次聚类与k-均值聚类算法
1. 原理 1.层次聚类:通过计算两类数据点间的相似性,对所有数据点中最为相似的两个数据点进行组合,并反复迭代这一过程并生成聚类树 2.k-means聚类:在数据集中根据一定策略选择K个点作为每个簇的初始中心,然后将数据划…...
【机器学习】包裹式特征选择之递归特征消除法
🎈个人主页:豌豆射手^ 🎉欢迎 👍点赞✍评论⭐收藏 🤗收录专栏:机器学习 🤝希望本文对您有所裨益,如有不足之处,欢迎在评论区提出指正,让我们共同学习、交流进…...
【ArcGIS】重采样栅格像元匹配问题:不同空间分辨率栅格数据统一
重采样栅格像元匹配问题:不同空间分辨率栅格数据统一 原始数据数据1:GDP分布数据2.1:人口密度数据2.2:人口总数数据3:土地利用类型 数据处理操作1:将人口密度数据投影至GDP数据(栅格数据的投影变…...
Qt 简约又简单的加载动画 第七季 音量柱风格
今天和大家分享两个音量柱风格的加载动画,这次的加载动画的最大特点就是简单,只有几行代码. 效果如下: 一共三个文件,可以直接编译运行 //main.cpp #include "LoadingAnimWidget.h" #include <QApplication> #include <QGridLayout> int main(int argc…...
【JS】数值精度缺失问题解决方案
方法一: 保留字符串类型,传给后端 方法二: 如果涉及到计算,用以下方法 // 核心思想 在计算前,将数字乘以相同倍数,让他没有小数位,然后再进行计算,然后再除以相同的倍数࿰…...
c++基础知识补充4
单独使用词汇 using std::cout; 隐式类型转换型初始化:如A a1,,此时可以形象地理解为int i1;double ji;,此时1可以认为创建了一个值为1的临时对象,然后对目标对象进行赋值,当对象为多参数时,使用(1…...
leetcode230. 二叉搜索树中第K小的元素
lletcode 230. 二叉搜索树中第K小的元素,链接:https://leetcode.cn/problems/kth-smallest-element-in-a-bst 题目描述 给定一个二叉搜索树的根节点 root ,和一个整数 k ,请你设计一个算法查找其中第 k 个最小元素(从 …...
医学大数据|文献阅读|有关“肠癌+机器学习”的研究记录
目录 1.机器学习算法识别结直肠癌中的免疫相关lncRNA signature 2.基于机器学习的糖酵解相关分子分类揭示了结直肠癌癌症患者预后、TME和免疫疗法的差异,2区7 3.整合深度学习-病理组学、放射组学和免疫评分预测结直肠癌肺转移患者术后结局 4.最新7.4分纯生信&am…...
Linux信号【systemV】
目录 前言 正文: 1消息队列 1.1什么是消息队列? 1.2消息队列的数据结构 1.3消息队列的相关接口 1.3.1创建 1.3.2释放 1.3.3发送 1.3.4接收 1.4消息队列补充 2.信号量 2.1什么是信号量 2.2互斥相关概念 2.3信号量的数据结构 2.4…...
node.js最准确历史版本下载
先进入官网:Node.js https://nodejs.org/en 嫌其他博客多可以到/release下载:Node.js,在blog后面加/release https://nodejs.org/en/blog/release/ 点击next翻页,同样的道理...
UE5 C++ 单播 多播代理 动态多播代理
一. 代理机制,代理也叫做委托,其作用就是提供一种消息机制。 发送方 ,接收方 分别叫做 触发点和执行点。就是软件中的观察者模式的原理。 创建一个C Actor作为练习 二.单播代理 创建一个C Actor MyDeligateActor作为练习 在MyDeligateAc…...
前端学习、CSS
CSS可以嵌入到HTML中使用。 每个CSS语法包含两部分,选择器和应用的属性。 div用来声明针对页面上的哪些元素生效。 具体设置的属性以键值对形式表示,属性都在{}里,属性之间用;分割,键和值之间用:分割。 因为CSS的特殊命名风格…...
Flink基本原理 + WebUI说明 + 常见问题分析
Flink 概述 Flink 是一个用于进行大规模数据处理的开源框架,它提供了一个流式的数据处理 API,支持多种编程语言和运行时环境。Flink 的核心优点包括: 低延迟:Flink 可以在毫秒级的时间内处理数据,提供了低延迟的数据…...
3. 文档概述(Documentation Overview)
3. 文档概述(Documentation Overview) 本章节简要介绍一下Spring Boot参考文档。它包含本文档其它部分的链接。 本文档的最新版本可在 docs.spring.io/spring-boot/docs/current/reference/ 上获取。 3.1 第一步(First Steps) …...
微信小程序之bind和catch
这两个呢,都是绑定事件用的,具体使用有些小区别。 官方文档: 事件冒泡处理不同 bind:绑定的事件会向上冒泡,即触发当前组件的事件后,还会继续触发父组件的相同事件。例如,有一个子视图绑定了b…...
dedecms 织梦自定义表单留言增加ajax验证码功能
增加ajax功能模块,用户不点击提交按钮,只要输入框失去焦点,就会提前提示验证码是否正确。 一,模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...
Axios请求超时重发机制
Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式: 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...
12.找到字符串中所有字母异位词
🧠 题目解析 题目描述: 给定两个字符串 s 和 p,找出 s 中所有 p 的字母异位词的起始索引。 返回的答案以数组形式表示。 字母异位词定义: 若两个字符串包含的字符种类和出现次数完全相同,顺序无所谓,则互为…...
【数据分析】R版IntelliGenes用于生物标志物发现的可解释机器学习
禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍流程步骤1. 输入数据2. 特征选择3. 模型训练4. I-Genes 评分计算5. 输出结果 IntelliGenesR 安装包1. 特征选择2. 模型训练和评估3. I-Genes 评分计…...
基于Java Swing的电子通讯录设计与实现:附系统托盘功能代码详解
JAVASQL电子通讯录带系统托盘 一、系统概述 本电子通讯录系统采用Java Swing开发桌面应用,结合SQLite数据库实现联系人管理功能,并集成系统托盘功能提升用户体验。系统支持联系人的增删改查、分组管理、搜索过滤等功能,同时可以最小化到系统…...
C++.OpenGL (14/64)多光源(Multiple Lights)
多光源(Multiple Lights) 多光源渲染技术概览 #mermaid-svg-3L5e5gGn76TNh7Lq {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-3L5e5gGn76TNh7Lq .error-icon{fill:#552222;}#mermaid-svg-3L5e5gGn76TNh7Lq .erro…...
CVE-2020-17519源码分析与漏洞复现(Flink 任意文件读取)
漏洞概览 漏洞名称:Apache Flink REST API 任意文件读取漏洞CVE编号:CVE-2020-17519CVSS评分:7.5影响版本:Apache Flink 1.11.0、1.11.1、1.11.2修复版本:≥ 1.11.3 或 ≥ 1.12.0漏洞类型:路径遍历&#x…...
C++.OpenGL (20/64)混合(Blending)
混合(Blending) 透明效果核心原理 #mermaid-svg-SWG0UzVfJms7Sm3e {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-icon{fill:#552222;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-text{fill…...
Vite中定义@软链接
在webpack中可以直接通过符号表示src路径,但是vite中默认不可以。 如何实现: vite中提供了resolve.alias:通过别名在指向一个具体的路径 在vite.config.js中 import { join } from pathexport default defineConfig({plugins: [vue()],//…...

