当前位置: 首页 > news >正文

18.HTTP协议(二)

一.概念回顾

建议先学上篇博客,再向下学习,上篇博客的链接如下:

https://blog.csdn.net/weixin_60668256/article/details/154835397?fromshare=blogdetail&sharetype=blogdetail&sharerId=154835397&sharerefer=PC&sharesource=weixin_60668256&sharefrom=from_link

二.http请求与响应的格式

1.http请求

2.http响应

三.http协议定制

#pragma once#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include "Common.hpp"const std::string Sep = "\r\n";
const std::string LineSep = " ";
const std::string BlankLine = Sep;class HttpRequest
{
public:HttpRequest(){}~HttpRequest(){}void Deserialize(std::string& request_str){std::cout << "#############################" << std::endl;std::cout << "解析之前 request_str: \n" << request_str;if(ParseOneLine(request_str,&_req_line,Sep)){//提取请求行内的详细字段ParseReqLine(_req_line,LineSep);}std::cout << "解析之后 request_str: \n" << request_str;Print();std::cout << "#############################" << std::endl;}void Print(){std::cout << "#############################" << std::endl;std::cout << "_method: " << _method << std::endl;std::cout << "_uri: " << _uri << std::endl;std::cout << "_version: " << _version << std::endl;}
private:void ParseReqLine(std::string& _req_line,const std::string sep){std::stringstream ss(_req_line);ss >> _method >> _uri >> _version;}
private:std::string _req_line;std::vector<std::string> _req_header;std::string _blank_line;std::string _body;//反序列化的过程中,细化我们解析的字段std::string _method;std::string _uri;std::string _version;
};class HttpResponse
{
private:std::string _resp_line;std::vector<std::string> _resp_header;std::string _blank_line;std::string _body;
};

1.Deserialize函数的实现

void Deserialize(std::string& request_str){if(ParseOneLine(request_str,&_req_line,Sep)){//提取请求行内的详细字段ParseReqLine(_req_line,LineSep);ParseHeader(request_str);_body = request_str;}}

a.ParseOneLine(请求行的拆分)

//1.正常字符串
//2.true && 空
//3.false && 空
bool ParseOneLine(std::string& str,std::string* out,const std::string& sep)
{auto pos = str.find(sep);if(pos == std::string::npos){return false;}*out = str.substr(0,pos);str.erase(0,pos+sep.size());return true;
}

b.ParseHeader(请求报头的拆分)

bool ParseHeader(std::string& request_str){std::string line;while(true){bool r = ParseOneLine(request_str,&line,Sep);if(r && !line.empty()){_req_header.push_back(line);}else if(r && line.empty()){_blank_line = Sep;break;}else{return false;}}return true;}

c.Print()的实现

void Print(){std::cout << "_method: " << _method << std::endl;std::cout << "_uri: " << _uri << std::endl;std::cout << "_version: " << _version << std::endl;for(auto& line : _req_header){std::cout << line << "\n" << std::endl;}std::cout << "_blank_line: " << _blank_line << std::endl;std::cout << "body: " << _body << std::endl;}

d.ParseHeaderkv()的实现

bool ParseHeaderkv(){std::string key,value;for(auto& header : _req_header){//Connection: keep-aliveif(SplitString(header,HeaderLineSep,&key,&value)){_header_kv.insert(std::make_pair(key,value));}}return true;}

e.Request总代码

class HttpRequest
{
public:HttpRequest(){}~HttpRequest(){}bool ParseHeaderkv(){std::string key,value;for(auto& header : _req_header){//Connection: keep-aliveif(SplitString(header,HeaderLineSep,&key,&value)){_header_kv.insert(std::make_pair(key,value));}}return true;}bool ParseHeader(std::string& request_str){std::string line;while(true){bool r = ParseOneLine(request_str,&line,Sep);if(r && !line.empty()){_req_header.push_back(line);}else if(r && line.empty()){_blank_line = Sep;break;}else{return false;}}ParseHeaderkv();return true;}void Deserialize(std::string& request_str){if(ParseOneLine(request_str,&_req_line,Sep)){//提取请求行内的详细字段ParseReqLine(_req_line,LineSep);ParseHeader(request_str);_body = request_str;}}void Print(){std::cout << "_method: " << _method << std::endl;std::cout << "_uri: " << _uri << std::endl;std::cout << "_version: " << _version << std::endl;for(auto& kv : _header_kv){std::cout << kv.first << " # " << kv.second << std::endl;}std::cout << "_blank_line: " << _blank_line << std::endl;std::cout << "body: " << _body << std::endl;}
private:void ParseReqLine(std::string& _req_line,const std::string sep){std::stringstream ss(_req_line);ss >> _method >> _uri >> _version;}
private:std::string _req_line;std::vector<std::string> _req_header;std::string _blank_line;std::string _body;//反序列化的过程中,细化我们解析的字段std::string _method;std::string _uri;std::string _version;std::unordered_map<std::string,std::string> _header_kv; 
};

2.http家目录

当用户只请求我们对应的首页或者/,那么就直接变成默认的index.html

用户的请求主要是放在我们的uri里面

所以,我们在收到对应的信息的时候,我们应该加上我们的默认页面路径

void ParseReqLine(std::string& _req_line,const std::string sep){std::stringstream ss(_req_line);ss >> _method >> _uri >> _version;_uri = defaulthomepage + _uri;}

所以,以后再去找资源,就全部都从defaulthomepage里面去找对应的资源了

3.获取对应请求的网页资源

std::string GetContent(){std::string content;std::ifstream in(_uri);if(!in.is_open()){return std::string();}std::string line;while(std::getline(in,line)){content += line;}in.close();return content;}

4.HttpResponse的实现

a.基本返回实现

对于浏览器和服务器的http版本来说,一般是不同的,我们传递消息时,一定要将该版本进行交换

对于我们的返回信息,要包含状态码和对应的状态状态码对应的string值

//对于http来说,任何请求都要有对应的应答
class HttpResponse
{
public:HttpResponse():_version(http_version),_blank_line(Sep){}~HttpResponse(){}void Build(HttpRequest& req){_content = req.GetContent();if(_content.empty()){//当前用户请求资源不存在_status_code = 404;req.SetUri(page404);_content = req.GetContent();}else{_status_code = 200;}_status_desc = CodeToDesc(_status_code);}void Serialize(std::string* resp_str){_resp_line = _version + LineSep + std::to_string(_status_code) + LineSep + _status_desc + Sep;_body = _content;//序列化*resp_str = _resp_line;for(auto& line : _resp_header){*resp_str += (line + Sep);}*resp_str += _blank_line;*resp_str += _body;}
private:std::string CodeToDesc(int code){switch(code){case 200:return "OK";case 404:return "Not Found";default:return std::string();}}
private://必备的要素std::string _version;int _status_code;std::string _status_desc;std::string _content;//最终要这四部分,构建应答std::string _resp_line;std::vector<std::string> _resp_header;std::string _blank_line;std::string _body;
};

浏览器显示如下:

b.访问\时添加默认路径

void Build(HttpRequest& req){std::string uri = req.Uri();// wwwroot/     ->  wwwroot/index.html// wwwroot/a/b  ->  wwwroot/a/b/index.htmlif(uri.back() == '/'){uri += firstpage;req.SetUri(uri);}_content = req.GetContent();if(_content.empty()){//当前用户请求资源不存在_status_code = 404;req.SetUri(page404);_content = req.GetContent();}else{_status_code = 200;}_status_desc = CodeToDesc(_status_code);}

前端开发主要是写wwwroot内部的内容,而我们后端开发,主要就是开发wwwroot外面的内容

我们通过图标来去向浏览器发送新的请求,是通过前端的<a>标签进行的

我们这里多加几个网页(AI生成即可)

5.http的其他字段

添加请求报头

void SetHeader(const std::string& k,const std::string& v){_header_kv[k] = v;}
void Build(HttpRequest& req){std::string uri = req.Uri();// wwwroot/     ->  wwwroot/index.html// wwwroot/a/b  ->  wwwroot/a/b/index.htmlif(uri.back() == '/'){uri += firstpage;req.SetUri(uri);}_content = req.GetContent();if(_content.empty()){//当前用户请求资源不存在_status_code = 404;req.SetUri(page404);_content = req.GetContent();}else{_status_code = 200;}_status_desc = CodeToDesc(_status_code);if(!_content.empty()){SetHeader("Content-Length",std::to_string(_content.size()));}for(auto& header : _header_kv){_resp_header.push_back(header.first + HeaderLineSep + header.second);}}

但是我们看不到是怎么回事?

所以我们可以采用二进制读写(文本和图片都能可以进行读取)

std::string GetContent(){std::string content;std::ifstream in(_uri,std::ios::binary);if(!in.is_open()){return std::string();}in.seekg(0,in.end);int filesize = in.tellg();in.seekg(0,in.beg);content.resize(filesize);in.read((char*)content.c_str(),filesize);in.close(); return content;}

我们现在是任何的访问内容都是给其返回一个字符串,浏览器自己可以进行解析(图片还是文本),但是我们的返回字段中,要加上对应的内容信息

std::string Suffix(){auto pos = _uri.rfind(".");if(pos == std::string::npos){return std::string(".html");}return _uri.substr(pos);}

这里的转换,我们可以直接简单设计一下

std::string SuffixToDesc(const std::string& suffix){if(suffix == ".html"){return "text/html";}else if(suffix == ".png"){return "image/png";}return "text/html";}

http://www.dtcms.com/a/613653.html

相关文章:

  • 【科技补全76】新概念英语点读工具NCE-Flow、在线文件管理器copyparty 部署指北
  • 添加某些应用程序使其能够用win+r启动
  • 免费的个人网站北京工程建设监理协会网站
  • 34_FastMCP 2.x 中文文档之FastMCP客户端高级功能:处理服务端发起的用户引导详解
  • 算法公司技术面试经验总结
  • 公路建设管理办公室网站网站建设到维护
  • 美国 TikTok 带货 GMV 翻倍:专线 + 纯净住宅 IP 的流量密码
  • [智能体设计模式] 第11章:目标设定与监控模式
  • Modbus RTU 转 Modbus TCP:物联网网关实现中药产线巴赫曼与三菱PLC互联
  • 商城网站都有哪 些功能济南网签查询系统
  • Flink20 SQL 窗口函数概述
  • Java基础 | SpringBoot实现自启动的方式
  • 【ZeroRange WebRTC】UDP无序传输与丢包检测机制深度分析
  • 零基础建设网站视频教程抚州的电子商务网站建设公司
  • qt显示类控件--- Label
  • 【深度学习】基于Faster R-CNN与HRNet的豆类品种识别与分类系统
  • 专业建设网站公司东莞阿里巴巴代运营
  • 【深度学习】YOLOv10n-MAN-Faster实现包装盒flap状态识别与分类,提高生产效率
  • 网站备案需要费用吗中国容桂品牌网站建设
  • 知识图谱与中医古籍的数智化融合:中医药多智能体大模型系统的未来展望
  • wordpress全站cdn法人变更在哪个网站做公示
  • 鸿蒙开发TypeScript第六课:对象
  • 【Linux日新月异(四)】CentOS 7进程管理深度指南:掌控系统生命线
  • 如何避免新手对 instanceof 的误解?
  • 每周AI看 | OpenAI发布GPT-5.1、网易云商自研内部知识问答Agent、商汤开源空间智能大模型
  • 移动端部署噩梦终结者:动态稀疏视觉Transformer的量化实战
  • 【LeetCode刷题】找到字符串中所有字母异位词
  • 榆林城乡建设规划官方网站中国室内设计师
  • oneinstack wordpress成都官网seo服务
  • Go语言编译 | 探讨Go语言编译原理与优化技巧