【Linux网络编程】第十一弹---HTTP协议全解析:从请求响应到方法与Header的详尽指南

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

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

目录

[1、HTTP 协议](#1、HTTP 协议)

[1.1、认识 URL](#1.1、认识 URL)

[​1.2、urlencode 和 urldecode](#1.2、urlencode 和 urldecode)

[1.3、HTTP 协议请求与响应格式](#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.6、HTTP 请求)

[1.3.7、HTTP 响应](#1.3.7、HTTP 响应)

1.3.8、基本的应答格式

[1.4、HTTP 的方法](#1.4、HTTP 的方法)

[1.4.1、HTTP 常见方法](#1.4.1、HTTP 常见方法)

[1.5、HTTP 常见 Header](#1.5、HTTP 常见 Header)

[1.5.1、关于 connection 报头](#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
相关推荐
siy23333 分钟前
[c语言日寄]结构体的使用及其拓展
c语言·开发语言·笔记·学习·算法
可涵不会debug5 分钟前
【C++】在线五子棋对战项目网页版
linux·服务器·网络·c++·git
AI+程序员在路上8 分钟前
C#调用c++dll的两种方法(静态方法和动态方法)
c++·microsoft·c#
清风-云烟30 分钟前
使用redis-cli命令实现redis crud操作
java·linux·数据库·redis·spring·缓存·1024程序员节
安和昂38 分钟前
effective Objective—C 第三章笔记
java·c语言·笔记
Rm39 分钟前
Linux 防火墙 Systemctl 常用命令速查
linux
四念处茫茫43 分钟前
【C语言系列】深入理解指针(2)
c语言·开发语言·visual studio
mit6.8241 小时前
What is Json?
c++·学习·json
LucianaiB1 小时前
C语言之图像文件的属性
c语言·开发语言·microsoft·c语言之图像文件的属性
孤寂大仙v1 小时前
【Linux】环境变量
linux·运维·服务器