个人主页: 熬夜学编程的小林

💗系列专栏: 【C语言详解】 【数据结构详解】【C++详解】【Linux系统编程】【Linux网络编程】

目录

1、HTTP 协议

1.1、认识 URL

​1.2、urlencode 和 urldecode

1.3、HTTP 协议请求与响应格式

1.3.1、代码修改 

1.3.2、Http.hpp

1.3.3、ServerMain.cc

1.3.4、腾讯云配置安全组(防火墙)

1.3.5、在浏览器中访问

1.3.5、修改Http.hpp中执行方法

1.3.6、HTTP 请求

1.3.7、HTTP 响应 

1.3.8、基本的应答格式

1.4、HTTP 的方法 

1.4.1、HTTP 常见方法

1.5、HTTP 常见 Header

1.5.1、关于 connection 报头


1、HTTP 协议

虽然我们说, 应用层协议是我们程序猿自己定的. 但实际上, 已经有大佬们定义了一些现成的, 又非常好用的应用层协议, 供我们直接参考使用. HTTP(超文本传输协议)就是其中之一。

在互联网世界中,HTTP(HyperText Transfer Protocol,超文本传输协议)是一个至关重要的协议。它定义了客户端(如浏览器)与服务器之间如何通信,以交换或传输超文本(如 HTML 文档)。

HTTP 协议是客户端与服务器之间通信的基础。客户端通过 HTTP 协议向服务器发送请求,服务器收到请求后处理并返回响应。HTTP 协议是一个无连接、无状态的协议,即每次请求都需要建立新的连接,且服务器不会保存客户端的状态信息

1.1、认识 URL

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

初步认识

深刻认识 

1.2、urlencode 和 urldecode

/ ? : 等这样的字符, 已经被 url 当做特殊意义理解了. 因此这些字符不能随意出现.比如, 某个参数中需要带有这些特殊字符, 就必须先对特殊字符进行转义.
转义的规则如下:
将需要转码的字符转为 16 进制,然后从右到左,取 4 位(不足 4 位直接处理),每 2 位做一位,前面加上%,编码成%XY 格式!

例如: 

使用特殊字符访问浏览器时,会进行编码(urlencode)与解码(urldecode)的过程! 

1.3、HTTP 协议请求与响应格式

编写代码见见http 请求与应答

拷贝上一弹的网络计算器的部分代码(InetAddr.hpp,LockGuard.hpp,Log.hpp,Makefile,ServerMain.cc,Socket.hpp,TcpServer.hpp),并适当修改代码进行测试!

1.3.1、代码修改 

修改TcpServer.hpp文件中的执行方法声明:

using service_t = std::function<std::string (std::string &requeststr)>;

TcpServer类的成员变量与构造函数同理!

class TcpServer
{
public:
    TcpServer(service_t service,uint16_t port = gport)
        :_port(port),
        _listensock(std::make_shared<TcpSocket>()),
        _isrunning(false),
        _service(service)
    {
        _listensock->BuildListenSocket(_port);
    }
private:
    uint16_t _port;
    SockSPtr _listensock;
    bool _isrunning;
    service_t _service; // // 执行方法
};

Execute()函数也需修改!

// 无法调用类内成员 无法看到sockfd
static void *Execute(void *args)
{
    ThreadData *td = static_cast<ThreadData *>(args);
    pthread_detach(pthread_self()); // 分离新线程,无需主线程回收
    
    std::string requeststr;
    // 后面不做请求的分离,我们认为读到的是一个完整的请求 -bug
    ssize_t n = td->_sockfd->Recv(&requeststr);
    if(n > 0)
    {
        std::string responsestr = td->_self->_service(requeststr); // 执行回调
        td->_sockfd->Send(responsestr);
    }
    
    td->_sockfd->Close();
    delete td;
    return nullptr;
}

1.3.2、Http.hpp

该类用于处理服务的回调函数

#pragma once

#include <iostream>
#include <string>

class HttpServer
{
public:
    HttpServer()
    {}
    std::string HandlerHttpRequest(std::string &req)
    {
        std::cout << "---------------------------------------------" << std::endl;
        std::cout << req;

        return std::string();
    }
    ~HttpServer()
    {}
};

注意: 此处的执行方法返回的是空串,后序再进行修改!

1.3.3、ServerMain.cc

ServerMain.cc文件创建TcpServer智能指针对象!

#include "TcpServer.hpp" // 会话层
#include "Http.hpp"

// ./calserver 8888
int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        std::cerr << "Usage: " << argv[0] << "local-port" << std::endl;
        exit(0);
    }

    uint16_t port = std::stoi(argv[1]);

    HttpServer hserver;

    std::unique_ptr<TcpServer> tsvr = std::make_unique<TcpServer>(
        std::bind(&HttpServer::HandlerHttpRequest, &hserver, std::placeholders::_1),
        port);
    tsvr->Loop();

    return 0;
}

1.3.4、腾讯云配置安全组(防火墙)

云服务器只有配置了安全组(防火墙)才能直接使用IP + 端口号在浏览器访问!

步骤一:执行服务端程序:

步骤二:安装telnet服务

步骤三:判断是否配置了安全组:

在cmd中执行命令 telnet ip port    !

出现上面的情况表示没有配置安全组!

步骤四:配置安全组(防火墙):

在腾讯云官网的服务器中配置!

 步骤五:再次判断是否配置了安全组

在cmd中执行命令 telnet ip port    !

此时表示配置成功!

1.3.5、在浏览器中访问

在浏览器中访问的前提是将服务端启动起来,在浏览器输入公网IP:端口号

1.3.5、修改Http.hpp中执行方法

执行方法中给客户端发送一些信息!

std::string HandlerHttpRequest(std::string &reqstr)
{
    std::cout << "---------------------------------------------" << std::endl;
    std::cout << reqstr;

    // return std::string();
    std::string responsestr = "HTTP/1.1 200 OK\r\n";
    responsestr += "Content-Type: test/html\r\n";
    responsestr += "\r\n";
    responsestr += "<html><h1>hello linux,hello net!<h2></html>";

    return responsestr;
}

错误示范(X) 

此处是因为方法中的代码错了一个英文,导致没有打印出来东西,而是下载内容!

正确示范(√)

修改HandlerHttpRequest()函数中的一个英文字母即可!

1.3.6、HTTP 请求

  • 首行: [方法] + [url] + [版本]
  • Header: 请求的属性, 冒号分割的键值对;每组属性之间使用\r\n 分隔;遇到空行表示 Header 部分结束
  • Body: 空行后面的内容都是 Body. Body 允许为空字符串. 如果 Body 存在, 则在Header 中会有一个 Content-Length 属性来标识 Body 的长度;

1.3.7、HTTP 响应 

  • 首行: [版本号] + [状态码] + [状态码解释]
  • Header: 请求的属性, 冒号分割的键值对;每组属性之间使用\r\n 分隔;遇到空行表示 Header 部分结束
  • Body: 空行后面的内容都是 Body. Body 允许为空字符串. 如果 Body 存在, 则在Header 中会有一个 Content-Length 属性来标识 Body 的长度; 如果服务器返回了一个 html 页面, 那么 html 页面内容就是在 body 中.

1.3.8、基本的应答格式

1.4、HTTP 的方法 

其中最常用的就是 GET 方法和 POST 方法. 

1.4.1、HTTP 常见方法

1. GET 方法(重点)
用途:用于请求 URL 指定的资源
示例:GET /index.html HTTP/1.1
特性:指定资源经服务器端解析后返回响应内容。

form表单

2. POST 方法(重点)
用途:用于传输实体的主体,通常用于提交表单数据。
示例:POST /submit.cgi HTTP/1.1
特性:可以发送大量的数据给服务器,并且数据包含在请求体中。

3. PUT 方法(不常用)
用途:用于传输文件,将请求报文主体中的文件保存到请求 URL 指定的位置。
示例:PUT /example.html HTTP/1.1
特性:不太常用,但在某些情况下,如 RESTful API 中,用于更新资源。
4. HEAD 方法
用途:与 GET 方法类似,但不返回报文主体部分,仅返回响应头。
示例:HEAD /index.html HTTP/1.1
特性:用于确认 URL 的有效性及资源更新的日期时间等。

5. DELETE 方法(不常用)
用途:用于删除文件,是 PUT 的相反方法。
示例:DELETE /example.html HTTP/1.1
特性:按请求 URL 删除指定的资源。
6. OPTIONS 方法
用途:用于查询针对请求 URL 指定的资源支持的方法。
示例:OPTIONS * HTTP/1.1
特性:返回允许的方法,如 GET、POST 等。

1.5、HTTP 常见 Header

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

1.5.1、关于 connection 报头

HTTP 中的 Connection 字段是 HTTP 报文头的一部分,它主要用于控制和管理客户端与服务器之间的连接状态。

核心作用

  • 管理持久连接:Connection 字段还用于管理持久连接(也称为长连接)。持久连接允许客户端和服务器在请求/响应完成后不立即关闭 TCP 连接,以便在同一个连接上发送多个请求和接收多个响应。

持久连接(长连接)

  • HTTP/1.1:在 HTTP/1.1 协议中,默认使用持久连接。当客户端和服务器都不明确指定关闭连接时,连接将保持打开状态,以便后续的请求和响应可以复用同一个连接。
  • HTTP/1.0:在 HTTP/1.0 协议中,默认连接是非持久的。如果希望在 HTTP/1.0上实现持久连接,需要在请求头中显式设置 Connection: keep-alive。

语法格式

  • Connection: keep-alive:表示希望保持连接以复用 TCP 连接
  • Connection: close:表示请求/响应完成后,应该关闭 TCP 连接

下面附上一张关于 HTTP 常见 header 的表格

字段名 含义 样例
Accept 客户端可接受的
响应内容类型
Accept: text/html,application/xhtml+xml,app
lication/xml;q=0.9,image/webp,image /apng,*/*;q=0.8
Accept
Encoding
客户端支持的数
据压缩格式
Accept-Encoding: gzip, deflate, br
Accept
Language
客户端可接受的
语言类型
Accept-Language: zh CN,zh;q=0.9,en;q=0.8
Host 请求的主机名和
端口号
Host: www.example.com:8080
User-Agent 客户端的软件环
境信息
User-Agent: Mozilla/5.0 (Windows NT10.0; Win64; x64)
AppleWebKit/537.36 (KHTML, likeGecko) Chrome/91.0.4472.124
Safari/537.36
Cookie 客户端发送给服
务器的 HTTP
cookie 信息
Cookie: session_id=abcdefg12345;user_id=123
Referer 请求的来源 URL Referer: http://www.example.com/previous_page.html
Content-Type 实体主体的媒体
类型
Content-Type: application/x-wwwform-urlencoded (对于表单提交) 或
Content-Type: application/json (对于JSON 数据)
Content-Length 实体主体的字节
大小
Content-Length: 150
Authorization 认证信息, 如用
户名和密码
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ== (Base64
编码后的用户名:密码)
Cache-Control 缓存控制指令 请求时: Cache-Control: no-cache 或 Cache-Control: max-age=3600; 响应时: Cache-Control: public, max age=3600
Connection 请求完后是关闭
还是保持连接
Connection: keep-alive 或 Connection: close
Date 请求或响应的日
期和时间
Date: Wed, 21 Oct 2023 07:28:00 GMT
Location 重定向的目标
URL(与 3xx 状
态码配合使用)
Location: http://www.example.com/new_location.html (与 302 状态码配合使用)
Server 服务器类型 Server: Apache/2.4.41 (Unix)
Last-Modified 资源的最后修改
时间
Last-Modified: Wed, 21 Oct 2023 07:20:00 GMT
ETag 资源的唯一标识
符, 用于缓存
ETag: "3f80f-1b6-5f4e2512a4100"
Expires 响应过期的日期
和时间
Expires: Wed, 21 Oct 2023 08:28:00 GMT

Logo

助力广东及东莞地区开发者,代码托管、在线学习与竞赛、技术交流与分享、资源共享、职业发展,成为松山湖开发者首选的工作与学习平台

更多推荐