HTTP协议讲解

前瞻:


认识URL
  


1.ip+port
2.平时上网,就是进程间通信
3.上网行为,1.获取资源 2.上传数据 相当于I/O
4.http协议采用tcp协议
网页 图片 音乐其实都是资源

Http请求
  
  
http request
  


Method:Get/Post
资源/路径:网页 图片 视频资源的路径
版本:http/1.0 短连接  http/1.1(主流) 长连接 基于一条连接发送许多请求

http如何读到完整的报文
a.一直读直到读到空行 分离报文和有效载荷
b.Content-Length:XXX——表示正文部分的长度  读到Content则正文有数据
如何对http进行反序列化   根据/r/n

http response
  

状态码:200 表示成功
         404 代表资源无法找到
  

请求行的内容
method url http_version    
在使用 std::stringstream 进行输入操作时,默认情况下是以空格作为分隔符的
此时可以将他们提取出来

 

`std::stringstream` s1;
 s1>>_method>>_url>>_http_version


资源url路径
要访问资源所在的路径

如何理解web根目录 /
可以将url中/提取出来,再识别成./wwwroot + firstpage 这样/访问就是访问首页
Content-Type:表示正文类型
  
a.你要求的所有资源都有资源类型
b.http response给浏览器响应的时候,会自动去识别资源类型去读取资源
所以我们没对资源进行访问时,都要有suffix后缀提供给浏览器识别读取


例如:
HTTP 请求或响应的 Content-Type 通常用于指定传输的数据类型。常见的 Content-Type 值:
text/html:HTML 文档

JPG 图像文件的 Content-Type 是:
image/jpeg
我们将suffix转换成shuffix后缀再交给responsecontent    
  
工具:Fiddler

请求方法GET/POST
上网行为
我们获取资源
我们向服务器传参 登陆 注册 搜索 POST+ 利用html的表单

GET:既可以获取资源也可以上传参数
POST:上传

request and response

#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <fstream>
using namespace std;
const string httpSep = "\r\n";
const string firstpagepath="firstpage.html";
const string workroot="./wwwroot";
const string spaceseq=" ";
class Request
{
public:
    Request() : _blank_line(httpSep),_path(workroot)
    {
    }
    bool GetLine(string &response, string *line)
    {
        int pos = response.find(httpSep);
        if (pos == string::npos)
            return false;

        *line = response.substr(0, pos);

        response.erase(0, pos + httpSep.size());
        return true;
    }
    void Deserialize(string &response)
    {
        string line;
        if (!GetLine(response, &line))
            return;
        _statu_line = line;
        while (true)
        {
            string line;
            bool ok = GetLine(response, &line);
            if (ok && !response.empty()) //_vec_line
            {
                _vec_header.push_back(line);
                continue;
            }
            else if (ok && response.empty())
            {
                _req_content = line;
                break;
            }
            else
            {
                break;
            }
        }
    }
    void Parse_statu_line()
    {
        std::stringstream s1(_statu_line);
        s1>>_method>>_url>>_http_version;

        if(_url=="/")
        {
            _path+=_url+firstpagepath;
        }
        else
        {
            _path+=_url;
        }
    }
    void Parse_suffix_type()
    {
        int pos=_path.find('.');
        if(pos==string::npos) 
        {
            _suffix=".html";
        }

        _suffix=_path.substr(pos);

    }
     std::string GetFileContentHelper(const std::string &path)
    {
        //文本
        // std::ifstream in(path, std::ios::binary);
        // if (!in.is_open())
        //     return "";
        // std::string content;
        // std::string line;
        // while(std::getline(in, line)) // BUG
        // {
        //     content += line;
        // }
        // in.close();
        // return content;

        std::ifstream in(path, std::ios::binary);
        if (!in.is_open())
            return "";
        in.seekg(0, in.end);
        int filesize = in.tellg();
        in.seekg(0, in.beg);

        std::string content;
        content.resize(filesize);
        in.read((char *)content.c_str(), filesize);

        // std::vector<char> content(filesize);
        // in.read(content.data(), filesize);

        in.close();

        return content;
    }
    
    void Parse()
    {
        Parse_statu_line();
        Parse_suffix_type();
    }
    void RequestDebug()
    {
        cout << "_statu_line:" << _statu_line << endl;
        for (auto &e : _vec_header)
        {
            cout << "---->" << e << endl;
        }
        cout << "_blank_line" << _blank_line << endl;
        cout << "_req_content:" << _req_content;
    }
    ~Request() {}
    string& Path()
    {
        return _path;
    }
    string& Suffix()
    {
        return _suffix;
    }
private:
    string _statu_line;
    vector<string> _vec_header;
    string _blank_line;
    string _req_content;

    string _method;
    string _url;
    string _http_version;
    string _path;
    string _suffix;
};
class Response{
    //"Http/1.0 200 ok\r\n";
    public:
    Response():_http_version("Http/1.0")
    {}
    bool SetCode(int code)
    {
        _code=to_string(code);
    }
    string ret_code()
    {
        return _code;
    }
    bool SetCodeDesc(const string  codedesc)
    {
        if(codedesc.empty()) return false;
        _code_desc=codedesc;
        return true;
    }
    void make_statu_line()
    {
        _statu_line=_http_version+spaceseq+_code+spaceseq+_code_desc+"\r\n";
    }
    void head_push(string line)
    {
        _head_vector.push_back(line);
    }
    void Set_content(string content)
    {
        _rescontent=content;
    }
    string serialize()
    {
        string retmesaage("");
        retmesaage+=_statu_line;
        for(auto & e: _head_vector)
        {
            retmesaage+=e;
        }
        retmesaage+=_rescontent;
        return retmesaage;
    }
    private:
    string _statu_line;
    vector<string> _head_vector;
    string _rescontent;


    string _http_version;
    string _code;
    string _code_desc;

};

main.cc

#include"TcpServer.hpp"
#include"HttpProtocol.hpp"
using namespace  std;
using namespace NET_work;
void Usage(std::string proc)
{
    std::cout << "Usage : \n\t" << proc << "local_port\n"
              << std::endl;
}
string _to_httptype(string type)
{
    if (type == ".html" || type== ".html")
        return "text/html";
    else if (type == ".png")
        return "image/png";
    else if (type == ".jpg")
        return "image/jpeg";
    else
    {
        return "text/html";
    }
}
string GetCodeDesc(int _code)
{
    switch (_code)
    {
    case 200: 
       return "OK";
    case 404: 
        return "Not Found";
    case 307:
        return "Temporary Redirect";
    default:
        break;
    }
}
string Http_Handel(string & requestmessage)
{
    Request req;
    req.Deserialize(requestmessage);
    req.Parse();
    req.RequestDebug();

    string responsemessage;
   
    string content=req.GetFileContentHelper(req.Path());
    Response res;
    int code=200;
    if(content.empty())
    {
        code=404;
        content=req.GetFileContentHelper("./wwwroot/404.html");
    }
    //code=307;
    res.SetCode(code);
    res.SetCodeDesc(GetCodeDesc(code));
    res.make_statu_line();
    res.Set_content(content);
    string httphead="Content-Length: " + std::to_string(content.size()) + "\r\n";
    res.head_push(httphead);
    httphead="Content_type: "+_to_httptype(req.Suffix())+"\r\n";
    res.head_push(httphead);

    if(res.ret_code()==to_string(307))
    {
         string httphead307;
         httphead307="Location:http://www.qq.com"+string("\r\n");
         res.head_push(httphead307);
    }
    httphead="Set-Cookie: "+string("username=bossface")+"\r\n";
    res.head_push(httphead);
    httphead="Set-Cookie: "+string("password=123465")+"\r\n";
    res.head_push(httphead);
    httphead="\r\n";
    res.head_push(httphead);
    //content;
    responsemessage=res.serialize();
    return responsemessage;

}   
int main(int argc, char *argv[])
{
    // 遗留问题,客户端只发了一次数据就退出了?
    if (argc != 2)
    {
        Usage(argv[0]);
        cerr << "Usage error" << endl;
        exit(0);
    }
    uint16_t port = stoi(argv[1]);
    TcpServer *server = new TcpServer(port,Http_Handel);
    server->Loop();
}

表单


  
FROM表单不写方法默认是GET方法

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>我的网站</title>
</head>

<body>
    <h4>This is my first paragraph.</h4>
    <!-- <a href="https://www.qq.com/">点我</a> -->
    <a href="http://8.137.19.140:8888/dira/dirb/x.html">跳转到登录</a>

    <form action="/dira/dirb/x.html" method="post">
        First name:<br>
        <input type="text" name="myname" value="aaaa">
        <br>
        Last name:<br>
        <input type="password" name="mypasswd" value="">
        <br><br>
        <input type="submit" value="登录">
    </form>

    <!-- <img src="/image/1.png" alt="cat"> -->
</body>

</html>

GET vs POST

GET利用url传参 POST利用正文传参

GET有字节数限制 POST没有字节数限制

GET私密性更差一点,但是GET/POST方法都不安全

我们要对数据进行加密和解密

HTTP的状态码
  

HTTP状态码对照表,HTML常用字符查询表,html特殊字符对照表_TendCode
例如200 success 404 failed 403 Forbiden 禁止访问 

设计一个404
可以直接创建一个404.html 当获取内容为空时 code设置为404 改为获取404.html文件中的内容
  


  
设计一个307 重定向功能
结合location
在响应报头里添加 Location: www.qq.com
重定向可以进行页面的跳转
301永久重定向和307临时重定向有什么区别?https://tendcode.com/tool/html-special-characters/
  

搜索网页,搜索的关键字会与无数个URL网络链接相关联(例如baidu),网站过期了,我们可以用301,去让用户获取新的链接,之后用户所有的访问都会去新的永久重定向的地址,旧地址就不使用了
  

cookie和session
http
1.无连接
2.无状态

网站为什么要一直认识我?
网站根据用户身份,要区分用户的权限。
那当点击网站内任意一链接时,为什么网站又不去一直让我登陆?
因为server无状态,所以无法一直识别用户,此时server会传入传入一个Cookie,Cookie字段会报曾经登陆过的账号密码自动保留,当下一次访问server就可以不用登陆了。
  
当将Cookie移除时,用户就需要重新登陆了
如何实现?
在http报头字段加入 Set-Cookie:username= ?
                   Set-Cookie: password=?
  


  
我们的Cookie有两类:文件级,内存级
保存的位置要么在文件要么在内存
tips:登陆网站后退出,当再次登陆,不需要输用户名密码则是在文件中储存。    
我们Cookie是基于会话管理的

我们自己设置一般的cookie存在一些问题
原因;当我们的电脑被入侵,黑客拿到了我们的Cookie,黑客可以直接拿我们的Cookie登陆我们的账号,就比如在之前我们的QQ特别容易被盗。
解决方案--->引入Sessionid
当用户输入账户和密码时,服务器返回的Cookie中不存用户的账户密码,而是存入Session,再构建Sessionid,Sessionid具有唯一性,返回给浏览器,这样我们用户的账户和密码就保存在了服务端,而不是客户端,而客户端再次访问时,客户端发给服务端Sessionid,服务端再用Sessionid去认证。
  
这时候又有个问题,黑客就算拿不到用户账户密码,也能拿到Sessionid,再通过服务端访问,Sessionid的引入好像只是解决了用户账户密码的暴漏问题。
这个问题我们无法解决,因为我们一旦把账户密码发送到客户端,用户信息就暴漏了。但是服务端有很多种策越解决这个问题,例如IP认证。一旦检测到陌生IP访问,服务端可以直接让Sessionid失效。
 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/901565.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

MyBatis缓存详解(一级缓存、二级缓存、缓存查询顺序)

固态硬盘缺陷&#xff1a;无法长时间使用&#xff0c;而磁盘只要不消磁&#xff0c;只要不受到磁影响&#xff0c;就可以长期使用&#xff0c;因此绝大多数企业还是使用磁盘来存储数据 像mysql这种关系型数据库中的数据存储在磁盘中&#xff0c;为方便查询&#xff0c;减少系统…

Linux文件类型和根目录结构

Linux文件类型和根目录结构 1.文件类型 字符文件类型说明~普通文件类似于Windows的记事本d目录文件类似于windows文件夹c字符设备文件串行端口设备&#xff0c;顺序读写&#xff0c;键盘b块设备文件可供存储的接口设备&#xff0c;随机读写&#xff0c;硬盘p管道文件用于进程…

工程项目管理软件怎么选?推荐7款实用工具

本文提及的有主流7款工程项目管理系统软件有: 1. Worktile&#xff1b;2. 广联达BIM5D&#xff1b;3. 泛普软件&#xff1b;4. 明源云工程&#xff1b;5. 飞书&#xff1b;6. Smartsheet&#xff1b;7. Procore。 很多工程项目管理人员常常头疼如何有效地管理多个项目&#xff…

保研考研机试攻略:python笔记(1)

&#x1f428;&#x1f428;&#x1f428;宝子们好呀 ~ 我来更新欠大家的python笔记了&#xff0c;从这一篇开始我们来学下python&#xff0c;当然&#xff0c;如果只是想应对机试并且应试语言以C和C为主&#xff0c;那么大家对python了解一点就好&#xff0c;重点可以看高分篇…

【机器学习】——numpy教程

文章目录 1.numpy简介2.初始化numpy3.ndarry的使用3.1numpy的属性3.2numpy的形状3.3ndarray的类型 4numpy生成数组的方法4.1生成0和1数组4.2从现有的数组生成4.3生成固定范围的数组4.4生成随机数组 5.数组的索引、切片6.数组的形状修改7.数组的类型修改8.数组的去重9.ndarray的…

接口测试(七)jmeter——参数化(RandomString函数)

一、RandomString函数 需求&#xff1a;模拟10个用户注册 1. 【工具】–>【函数助手对话框】 2. 选择RandomString函数 假设手机号码前3位设置为固定数值136&#xff0c;后8位可用RandomString函数随机产生数值 ① Random string length&#xff1a;8&#xff08;随机长度…

记录element-ui改造select显示为table,并支持多查询条件

最近遇到的一个需求 &#xff0c; 很有趣&#xff0c;是需要一个select组件&#xff0c;要求显示工号&#xff0c;员工姓名&#xff0c;以及区域 三个字段&#xff0c;并且要支持三个字段的查询。显然element原生的组件不适用&#xff0c;这时候我们需要改造一下&#xff0c;把…

基于大数据 Python Vue 美食推荐可视化系统(源码+LW+部署讲解+数据库)

&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; 会持续一直更新下去 有问必答 一键收藏关注不迷路 源码获取&#xff1a;https://pan.baidu.com/s/1aRpOv3f2sdtVYOogQjb8jg?pwdjf1d 提取码: jf1d &#…

Java后端面试题:Java基础篇

目录 Java基础 1.请你说说Java中基本数据类型的bit长度&#xff1f; 2.switch支持哪些数据类型&#xff1f;支持long么&#xff1f; 3.讲一下常见编码方式&#xff1f; 4.char能不能存储中文&#xff1f; 5.为什么数组索引从0开始呢&#xff1f;假如从1开始不行吗&#xf…

w003基于Springboot的图书个性化推荐系统的设计与实现

&#x1f64a;作者简介&#xff1a;多年一线开发工作经验&#xff0c;原创团队&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的网站项目。 代码可以查看文章末尾⬇️联系方式获取&#xff0c;记得注明来意哦~&#x1f339;赠送计算机毕业设计600个选题excel文…

Git 课程任务

破冰和创建项目 https://github.com/WangXiuhao/loveailab

CORE 安全与身份认证《1》 UseRouting 、UseEndpoints

认证、授权、确权与鉴权 路由 web的请求到达后端服务时&#xff0c;controller(控制器)会处理传入的http请求并响应用户操作&#xff0c; 请求的url会被映射到控制器的操作方法上。 此映射过程由应用程序中定义的路由规则完成。 》》》net core 在中间件中的鉴权授权的位置一…

rtp协议:rtcp包格式和传输间隔

RTP Control Protocol -- RTCP-rtp控制协议 实时传输控制协议&#xff08;RTCP&#xff09;基于对会话中的所有参与者定期传输控制包&#xff0c;使用与数据包相同的分发机制。底层协议必须提供数据包和控制包的多路复用&#xff0c;例如使用UDP时使用不同的端口号。RTCP执行四…

Golang | Leetcode Golang题解之第501题二叉搜索树中的众数

题目&#xff1a; 题解&#xff1a; func findMode(root *TreeNode) (answer []int) {var base, count, maxCount intupdate : func(x int) {if x base {count} else {base, count x, 1}if count maxCount {answer append(answer, base)} else if count > maxCount {ma…

一站式学习 Shell 脚本语法与编程技巧,踏出自动化的第一步

文章目录 1. 初识 Shell 解释器1.1 Shell 类型1.2 Shell 的父子关系 2. 编写第一个 Shell 脚本3. Shell 脚本语法3.1 脚本格式3.2 注释3.2.1 单行注释3.2.2 多行注释 3.3 Shell 变量3.3.1 系统预定义变量&#xff08;环境变量&#xff09;printenv 查看所有环境变量set 查看所有…

RK3568平台(基础篇)预编译命令原理

一.宏定义(#define)是什么 #define 可以将一对文本进行替换,在编译器读到需要被替换的文本的时候,会将这些文本全部替换成我们给定的文本。 如下是一个宏的定义: #define A 100 二.预编译 预处理命令 #if、#endif、#undef、#ifdef、#else、#elif 在接触#if、#undef这…

图片尺寸怎样能快速修改?图片改尺寸的4款在线工具

图片怎么压缩调整大小呢&#xff1f;现在的图片随着质量或者尺寸都会比较大&#xff0c;在很多平台上传时会导致无法使用&#xff0c;需要按照要求调整图片大小后才能够正常使用&#xff0c;那么如何操作能够快速修改图片大小呢&#xff1f;下面来给大家分享图片改大小的4款在线…

使用virtualenv/Anaconda/Miniconda创建python虚拟环境

自带venv 免安装直接使用 虚拟环境是创建一种隔离的工作空间&#xff0c;在该工作空间中可以安装不同的库&#xff0c;而不影响其他的项目。其中&#xff0c;python自带的venv&#xff0c;就可以很好的创建虚拟环境了。 # 创建虚拟环境 python -m venv venv# windows系统激活…

Linux -- 共享内存(2)

目录 命令 ipcs -m &#xff1a; 命令 ipcrm -m shmid&#xff1a; 共享内存的通信&#xff1a; 为什么共享内存更高效&#xff1f; 代码&#xff1a; ShmClient.cc&#xff1a; ShmServer.cc&#xff1a; 结果&#xff1a; 如何让共享内存实现同步&#xff1f; 代码&a…

119.WEB渗透测试-信息收集-ARL(10)

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a; 易锦网校会员专享课 上一个内容&#xff1a;118.WEB渗透测试-信息收集-ARL&#xff08;9&#xff09; 释放完成后&#xff0c;点击创…