Linux---HTTP协议

HTTP

HTTP协议(Hypertext Transfer Protocol,超文本传输协议)是一种应用层协议,主要用于在Web浏览器和Web服务器之间传输数据。

一、认识URL

平时我们俗称的 " 网址 " 其实就是说的 URL

http请求样例

看起来是一行一行的,但是本质还是一个大字符串,中间以换行符分割,跟我们在自定义协议时操作一样,通过换行对字符串进行解析

如何理解web根目录?

web根目录实际就是服务器上的一个指定的目录,里面存放了所有http的资源,如果请求url= / ,我们请求的是默认首页,我们会对请求的路径进行拼接,从而找到服务器中的某个资源,其他情况也是同理,都需要服务器进行相关的路径处理。

std::string GetFileContent(std::string path) // 读相应目录下的文件资源
{
    std::ifstream in(path,std::ifstream::binary);
    std::string content;
    if (!in.is_open())
        return "";
    in.seekg(0,in.end);
    size_t n = in.tellg();
    in.seekg(0,in.beg);
    std::vector<char> v(n);
    in.read(v.data(),v.size());
    in.close();
    return std::string(v.begin(),v.end());
}

std::string Handler(std::string &request)
{
    HttpRequest req;
    req.Deserialize(request);// 反序列化http请求
    req.Parse();// 解析 http 请求
    req.Debug();

    //创建响应报文
    std::string httpstatusline = "http/1.1 200 ok"; //响应行
    std::string content = GetFileContent(req.Path()); // 响应正文
    std::string httpheader = "Content-Length: " + std::to_string(content.size()) + "\r\n";// 相应报头
    httpheader += "\r\n"; // 空行
    std::string httpresponse = httpstatusline + httpheader + content;
    return httpresponse;
}

二、Get/post

我们上网不仅仅可以获取资源,也可以上传数据,可以结合html进行传参,如登录、注册、搜索等都需要我们向服务器传递数据。

Get:可以用来获取资源,也能用来传递参数

post:传递参数,通过正文进行传输

GET vs POST

  • GET用url进行传参,POST请求正文传参
  • url传参,字节个数有限制,POST方法,参数没有限制
  • GET私密性更差一些,因为输入的参数会回显出来

但是GET和POST都不安全,GET能被看到,POST是明文传输,可以被捕捉到,安全和加密有关

一些其他方法的介绍

方法说明支持的http版本
PUT传输文件1.0、1.1
HEAD获取报文首部1.0、1.1
DELETE删除文件1.1、1.1
OPTIONS询问支持的方法1.1
TRACE追踪路径1.1
CONNECT要求用隧道协议连接代理1.1

三、http的状态码

类别原因短语
1XXInformation (信息性状态码)接收的请求正在处理
2XXSuccess (成功状态码)请求正常处理完毕
3XXRedirection (重定向状态码)需要进行附加操作以完成请求
4XXClient Error (客户端错误码)服务器无法处理请求
5XXServer Error (服务器错误状态码)服务器处理请求出错

最常见的状态码, 比如 200(OK), 404(Not Found), 403(Forbidden), 302(Redirect, 重定向), 504(Bad Gateway) 

简单说明一下:

  1. 1xx(信息性状态码):表示请求已经接收,继续处理。例如:
    • 100 Continue:客户端应继续其请求。
    • 101 Switching Protocols:服务器根据客户端的请求切换协议。
  2. 2xx(成功状态码):表示请求已经被成功接收、理解、并处理。例如:
    • 200 OK:请求成功,成功被服务器接收、理解、并接受。
    • 201 Created:请求已经被服务器接收并创建了新的资源。
    • 204 No Content:服务器成功处理了部分GET请求,但没有返回任何内容。
  3. 3xx(重定向状态码):表示请求需要进一步操作,以完成请求。例如:
    • 301 Moved Permanently:被请求的资源已永久移动到新位置,将来任何对此资源的引用都应该使用本响应返回的URI。
    • 302 Found(或302 Moved Temporarily):请求的资源现在临时从不同的URI响应请求。
  4. 4xx(客户端错误状态码):表示客户端的请求有问题。例如:
    • 400 Bad Request:请求错误,通常是访问的域名未绑定引起。
    • 403 Forbidden:禁止访问。
  5. 5xx(服务器错误状态码):表示服务器处理请求时出现了错误

这里挑几个重要的说一下

1、404 Not Found

当我们访问的资源不存在时,就会返回,具体的实现就是将正文部分的内容变成下面的网页内容

2、307 Temporary Redirect  临时重定向

需要配合报头"Location: 网页链接"使用

3、301 Moved Permanently  永久移动

用法和307相同,但是两者的应用场景不一样

307:应用于页面的跳转,比如跳转到登录或注册页面

301:应用于当网络域名改变/网站过期,可以通过它来重定向之前的链接,让它指向新的域名网址

四、http的报头字段

HTTP 常见 Header
  • Content-Type: 数据类型(text/html等)
  • Content-Length: Body的长度
  • Host: 客户端告知服务器, 所请求的资源是在哪个主机的哪个端口上
  • User-Agent: 声明用户的操作系统和浏览器版本信息
  • referer: 当前页面是从哪个页面跳转过来的
  • location: 搭配3xx状态码使用, 告诉客户端接下来要去哪里访问
  • Cookie: 用于在客户端存储少量信息. 通常用于实现会话(session)的功能

注意:请求的所有资源都有后缀,后缀决定了文件的类型。浏览器可以通过正文部分的文件后缀知道文件类型,但是有些浏览器无法自动识别文件类型,需要通过Content-Type来获取文件类型,所以http有专门的文件后缀和Content-Type的映射表,下面是网上截取的一部分

五、Cookie和session

HTTP协议中的无连接和无状态是其两个重要特性。

  • 首先,无连接的含义是限制每次连接只处理一个请求。当服务器处理完客户的请求并收到客户的应答后,连接就会断开。这种设计方式的主要目的是节省传输时间,使得请求时建立连接,请求完成后释放连接,以便尽快将资源释放出来服务其他客户端。尽管无连接可以提高效率,但在某些情况下也可能导致额外的开销,因为每次请求都需要重新建立连接。然而,HTTP/1.1版本引入了Keep-Alive功能,使得客户端到服务器端的连接可以持续有效,当出现对服务器的后继请求时,可以避免重新建立连接。
  • 其次,无状态指的是协议对于事务处理没有记忆能力,服务器不知道客户端是什么状态。即我们给服务器发送HTTP请求之后,服务器根据请求会给我们发送数据过来,但是发送完不会记录任何信息。这意味着每个HTTP请求都是独立的,服务器不会记住前一个请求的状态或信息。这种设计方式简化了服务器的实现,并减轻了其负担,但也带来了一些问题。例如,由于每个请求都是独立的,单个请求所需要的所有信息都必须包含在请求中一次发送到服务器,这可能导致单个消息的结构变得复杂,需要支持大量的元数据。

为了解决HTTP无状态的问题,人们提出了多种方案,如使用cookie进行身份验证和状态管理。这样,服务器可以通过cookie来识别不同的客户端和它们的会话状态,从而在一定程度上模拟有状态的行为。

实际在使用浏览器访问网页时,尤其是那种需要vip身份才能访问特定资源的网站,都会要求我们去登录注册,用来标识每一个用户,但http是无状态的,即服务器不会记录用户的信息,所以每次我们在访问时,都需要发送身份信息,如果每次都需要用户手动输入,用户肯定会有砸掉电脑的冲动,所以浏览器可以用cookie对用户信息作记录,每次访问网页就可以自动帮我们在请求报文中加上我们的用户信息。

cookie分为内存级和文件级:

  • 内存级:将信息存放在浏览器进程的上下文中,只在进程运行时有效,一旦关闭再打开就失效了
  • 文件级:将信息存放在浏览器软件的特定目录的文件中,一直有效,除非手动删除/修改文件内容

通过把"Set-Cookie: username=zxws"这样的语句添加到http报头字段实现Cookie

这种基于Cookie实现的就是会话管理

但是这种会话管理并不安全,因为我们是用账户密码直接进行的http请求,很容易被别人拿到,为了加强安全性,我们一般将用户的账户和密码哈希成一个标识符sessionid,用它进行身份的验证

 附录

// HttpProtocol.hpp
// 仅仅是模拟实现最简单的http的请求和响应的基本功能
// 代码并不全面和严谨,仅仅是为了方便我们直观的认识和了解http底层到底是如何做的
// 可以用网络套接字通信模拟实现一个简单的http网页服务,有兴趣可以尝试一下
#pragma once
#include "TcpServer.hpp"
#include <string>
#include <vector>
#include <sstream>
#include <fstream>
const std::string HttpSeq = "\r\n";
const std::string wwwroot = "./wwwroot";
const std::string homepage = "index.html";

class HttpRequest
{
public:
    HttpRequest() : _path(wwwroot)
    {
    }

    bool GetLine(std::string &request, std::string *line)
    {
        auto pos = request.find(HttpSeq);
        if (pos == std::string::npos)
            return false;
        *line = request.substr(0, pos);
        request.erase(0, pos + HttpSeq.size());
        return true;
    }

    void Deserialize(std::string request)
    {
        std::string line;
        bool ok = GetLine(request, &line);
        if (!ok)
            return;
        _req_line = line;
        while (1)
        {
            ok = GetLine(request, &line);
            if (ok)
            {
                if (line.empty())
                {
                    _req_content = request;
                    break;
                }
                else
                {
                    _req_header.emplace_back(line);
                }
            }
            else
            {
                break;
            }
        }
    }

    void Parse()
    {
        ParseLine();

        if (_url == "/")
        {
            _path += _url;
            _path += homepage;
        }
        else
        {
            _path += _url; // ps:需要处理一些只有路径没有文件资源的问题
        }
    }

    std::string Suffix()
    {
        size_t pos = _path.rfind('.');
        if (pos == std::string::npos)
            return "";
        return _path.substr(pos + 1);
    }

    std::string GetFileContentHelper(const std::string &path)
    {
        std::ifstream in(path, std::ifstream::binary);
        std::string content;
        if (!in.is_open())
            return "";
        in.seekg(0, in.end);
        size_t n = in.tellg();
        in.seekg(0, in.beg);
        std::vector<char> v(n);
        in.read(v.data(), v.size());
        in.close();
        return std::string(v.begin(), v.end());
    }

    std::string GetFileContent()
    {
        return GetFileContentHelper(_path);
    }

    void ParseLine()
    {
        std::stringstream ss(_req_line);
        ss >> _method >> _url >> _version;
    }

    std::string Path()
    {
        return _path;
    }

    void Debug()
    {
        std::cout << _req_line << std::endl;
        for (auto line : _req_header)
        {
            std::cout << line << std::endl;
        }
        std::cout << _req_blank << std::endl;
        std::cout << _req_content << std::endl;

        // std::cout << _method << std::endl;
        // std::cout << _url << std::endl;
        // std::cout << _version << std::endl;
    }

    std::string Get_404()
    {
        return GetFileContentHelper("./wwwroot/404.html"); // 该404.html网页大家可以自己写
    }

private:
    std::string _req_line;
    std::vector<std::string> _req_header;
    std::string _req_blank = "";
    std::string _req_content;

    // method url 版本号
    std::string _method;
    std::string _url;
    std::string _version;
    std::string _path;

    std::string _suffix;
};

class HttpResponce
{
public:
    HttpResponce() : _version("http/1.1"), _status_code(200), _status_code_desc("ok"), _resp_blank("\r\n")
    {
    }
    void MakeStatusLine()
    {
        _status_line = _version + " " + std::to_string(_status_code) + " " + _status_code_desc;
    }

    void SetCode(int code)
    {
        _status_code = code;
    }

    void SetDesc(const std::string &desc)
    {
        _status_code_desc = desc;
    }

    void AddHeader(const std::string &header)
    {
        _resp_header.emplace_back(header);
    }

    void AddContent(const std::string &content)
    {
        _resp_content = content;
    }

    std::string Serialize()
    {
        std::string res = _status_line + HttpSeq;
        for (auto &header : _resp_header)
            res += header;
        res += _resp_blank;
        res += _resp_content;
        // std::cout << res << std::endl;
        return res;
    }

private:
    std::string _status_line;
    std::vector<std::string> _resp_header;
    std::string _resp_blank;
    std::string _resp_content;

    std::string _version;          // 版本号
    int _status_code;              // 状态码
    std::string _status_code_desc; // 状态信息
};
  • 25
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Linux-Telnet 是一种网络工具,用于在计算机之间建立远程连接。它基于Telnet协议(远程登录协议),可以通过命令行界面在远程主机上进行操作和管理。Linux-Telnet 具有以下特点和功能: 1. 远程登录:使用Linux-Telnet,可以从本地计算机远程登录到目标计算机。通过输入目标计算机的IP地址或主机名,可以建立与目标计算机的安全连接。 2. 命令行界面:Linux-Telnet 提供一个命令行界面,用户可以在远程主机上执行各种命令。这使得用户可以执行类似于登录到本地计算机上一样的操作,例如查看和编辑文件、执行程序或设置系统参数。 3. 文件传输:通过Linux-Telnet,用户可以在本地计算机和远程主机之间进行文件传输。用户可以通过简单的命令将文件从本地传输到远程主机,或从远程主机下载文件到本地。 4. 远程管理:Linux-Telnet 可以用于远程管理目标计算机。管理员可以使用Linux-Telnet执行系统管理任务,如用户管理、服务配置、网络设置等。 5. 安全性:Linux-Telnet 连接通常是明文的,容易受到黑客攻击。为了增加安全性,可以在Linux-Telnet中启用加密功能,以确保连接的保密性。 总之,Linux-Telnet 是一种强大的远程登录工具,可以在Linux系统上进行远程操作和管理。尽管存在一些安全风险,但通过适当的配置和实践,可以最大程度地减少潜在的风险。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值