一、概念
HTTP(HyperText Transfer Protocol,超文本传输协议)是一种用于分布式、协作式、超媒体信息系统的网络协议。它定义了客户端和服务器之间请求和响应的格式。HTTP 是基于TCP/IP协议的应用层协议,通常用于网页浏览。
超文本:超链接&文本
二、特性
1、C/S模型
总是客户端向服务端发送请求(request),服务端处理请求并做出回复(respond),请求和回应一一对应,这样的请求回应组合称为HTTP中的事务,不同事务之间相互独立,在应用层具有无连接性(逻辑上断开了连接,实际上可能没有断开)。
2、无状态
HTTP协议本身是无状态的,这意味着服务器不会在请求之间保存任何关于客户端状态的信息。
3、可靠性
底层采用tcp协议传输,保证了可靠性。
三、URI/URL
URI(Uniform Resource Identifier,统一资源标识符)和URL(Uniform Resource Locator,统一资源定位符)是互联网上用于标识资源的两种重要概念。
URI(统一资源标识符)
URI是一种用于标识资源的字符串,它提供了一种唯一的方式来标识互联网上的资源。URI可以进一步分为两种类型:
-
URL(统一资源定位符):URL是URI的一种,它不仅标识资源,还提供了定位资源的方法,即如何访问该资源。URL包含了访问资源所需的所有信息,如协议、服务器地址、路径等。
-
URN(Uniform Resource Name,统一资源名称):URN是URI的另一种类型,它用于持久、唯一地标识资源,但不包含如何访问资源的信息。URN通常用于那些不会频繁改变位置的资源,如书籍、文章等。
URL(统一资源定位符)
URL是URI的一种,它提供了一种具体的方式来定位和访问互联网上的资源。一个典型的URL包含以下几个部分:
-
协议(Scheme):指定访问资源所使用的协议,如
http
、https
、ftp
等。 -
服务器地址(Authority):指定资源所在的服务器地址,通常包括域名和端口号(如果非默认端口)。
-
路径(Path):指定资源在服务器上的路径。
-
查询字符串(Query):可选,用于传递额外的参数信息,如搜索关键词、页面编号等。
-
片段标识符(Fragment):可选,用于指向资源内部的特定部分,如网页中的某个章节。
示例:https://www.example.com/path/to/resource?query=param#fragment
https
:协议www.example.com
:服务器地址/path/to/resource
:路径?query=param
:查询字符串#fragment
:片段标识符
四、MIME
MIME(Multipurpose Internet Mail Extensions,多用途互联网邮件扩展)是一种互联网标准,用于处理不同格式的电子邮件内容。它最初被设计用于电子邮件,但后来也被广泛应用于HTTP协议中,用于定义和传输不同类型的数据。
MIME的主要目的是:
-
定义数据格式:MIME类型(也称为媒体类型)用于指定文件或消息内容的格式。例如,
text/html
表示HTML文档,image/jpeg
表示JPEG图片,application/json
表示JSON数据等。 -
支持多种数据类型:MIME允许电子邮件和网页支持多种数据类型,包括文本、图片、音频、视频等。
-
编码机制:为了确保数据在传输过程中的完整性,MIME定义了一种编码机制,如Quoted-printable和Base64,用于处理非ASCII字符和二进制数据。
-
头部信息:MIME头部信息用于描述消息的内容和格式。例如,在HTTP响应中,
Content-Type
头部用于指定响应体的MIME类型。
一些常见的MIME类型包括:
text/plain
:纯文本文件,如TXT文件。text/html
:HTML文档。image/jpeg
:JPEG图片。image/png
:PNG图片。image/gif
:GIF图片。application/pdf
:PDF文档。application/json
:JSON数据。application/xml
:XML数据。multipart/form-data
:用于表单数据的传输,允许在单个请求中发送多个数据字段。
五、探究HTTP报文结构
报文的结构:
- 报头
- 载荷
1、请求报文
可以接受HTTP接受请求的服务端程序
class HttpServer{
public:
HttpServer(string ip,unsigned short port)
:_sockfd(-1),_ip(ip),_port(port)
{}
~HttpServer(){
if(_sockfd>0){
close(_sockfd);
}
}
void start();
void recvMsg();
string response();
private:
int _sockfd;
string _ip;
unsigned short _port;
};
void HttpServer::start(){
_sockfd=::socket(AF_INET,SOCK_STREAM,0);
if(_sockfd<0){
perror("socket");
return ;
}
int reuse=1;
int ret=::setsockopt(_sockfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse));
if(ret<0){
perror("setscokopt");
return ;
}
struct sockaddr_in serverAddr;
::bzero(&serverAddr,sizeof(serverAddr));
serverAddr.sin_family=AF_INET;
serverAddr.sin_port=htons(_port);
serverAddr.sin_addr.s_addr=inet_addr(_ip.c_str());
ret=::bind(_sockfd,(struct sockaddr *)&serverAddr,sizeof(struct sockaddr_in));
if(ret<0){
perror("bind");
return;
}
::listen(_sockfd,50);
}
void HttpServer::recvMsg(){
while(true){
int netfd=::accept(_sockfd,nullptr,nullptr);
char buf[4096]={0};
ssize_t sret=recv(netfd,buf,sizeof(buf),0);
cout<<"sret="<<sret<<" buf="<<buf<<endl;
string resp=response();
send(netfd,resp.c_str(),resp.size(),0);
close(netfd);
}
}
通过浏览器充当客户端向该程序发送请求,该程序执行接受请求并打印的操作,获得的http请求报文如下:
sret=481 buf=GET / HTTP/1.1 #方法 路径 版本
Host: 192.168.80.132:1234 #地址
Connection: keep-alive #长连接
Content-Length: 0 #报文长度
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36 Edg/130.0.0.0
#客户端类型
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
请求报文的报头结构如上图所示:
- 起始行:方法+路径+版本 (\r\n)
- 若干键值对(\r\n)
- 空行(报头长度未知,用来空行判断报头结束的标准,报文长度记载在报头,长度已知)(\r\n)
请求报文中的方法种类:
-
GET:用于请求从服务器检索特定资源。GET请求应该只检索数据而不产生其他效果。GET是最常用的方法,用于获取网页内容。
-
POST:用于向服务器提交数据进行处理(例如,提交表单或上传文件)。POST请求可能会导致新资源的创建或现有资源的修改。
-
PUT:用于上传文件至服务器。PUT请求通常用于更新现有资源或创建新资源。
-
DELETE:用于请求服务器删除指定的资源。
-
HEAD:请求获取与GET请求相同的响应,但没有响应体。主要用于检查资源是否存在,以及获取资源的元数据。
-
OPTIONS:用于描述目标资源的通信选项。它允许客户端查看服务器的性能。
-
PATCH:用于对资源进行部分修改。与PUT不同,PATCH只更新资源的部分内容,而不是整个资源。
-
CONNECT:用于将请求连接转换为一个透明TCP/IP隧道,常用于SSL加密服务器的链接(通过代理)。
-
TRACE:用于沿着请求/响应链回显收到的请求,测试或诊断问题。
HTTP版本:
HTTP1.0和1.1的区别:1.1支持连接复用,节省了处理TCP连接的时间
2、响应报文
在linux环境执行curl -I 域名(www.xx.com)可以得到响应报文:
HTTP/1.1 301 Moved Permanently
Server: nginx
Date: Mon, 28 Oct 2024 11:00:09 GMT
Content-Type: text/html
Content-Length: 162
Connection: keep-alive
Location: https://dn.com/en-us/sale/jb.com
响应报文的报头结构:
- HTTP版本+状态码
- Server:服务器名称
- Content-Type:MIME类型
- Content-Length:报文长度
HTTP状态码:
-
1xx(信息性状态码):表示接收的请求正在处理。
100 Continue
:服务器已接收到请求的初始部分,客户端应继续发送其余部分。101 Switching Protocols
:服务器已理解请求,并将通过Upgrade头转换到不同的协议。
-
2xx(成功状态码):表示请求已成功被服务器接收、理解、并接受。
200 OK
:请求成功。201 Created
:请求成功,并且服务器创建了新的资源。202 Accepted
:服务器已接受请求,但尚未处理。
-
3xx(重定向状态码):表示需要进一步操作以完成请求。
301 Moved Permanently
:请求的资源已被永久移动到新位置。302 Found
:请求的资源临时被移动到另一个URI。304 Not Modified
:自从上次请求后,资源未修改过。
-
4xx(客户端错误状态码):表示客户端似乎有错误。
400 Bad Request
:服务器无法理解请求,可能是由于客户端错误。401 Unauthorized
:请求需要用户的身份认证。403 Forbidden
:服务器理解请求,但是拒绝执行。404 Not Found
:服务器找不到请求的资源。408 Request Timeout
:请求超时。
-
5xx(服务器错误状态码):表示服务器在处理请求的过程中发生了错误。
500 Internal Server Error
:服务器遇到了一个未曾预料的状况,导致无法完成对请求的处理。501 Not Implemented
:服务器不支持请求的功能,无法完成请求。503 Service Unavailable
:服务器目前无法处理请求,可能是由于过载或停机维护。
服务端向客户端发送报文:
string HttpServer::response(){
string startLine="HTTP/1.1 200 OK\r\n";
string headers="Server: kkHttpServer\r\n";
string body="<html>Hello World</html>";
headers+="Content-Type: text/plain\r\n";
headers+="Content-Length: "+std::to_string(body.size())+"\r\n";
string emptyLine="\r\n";
return startLine+headers+emptyLine+body;
}
浏览器客户端得到html文件并展示: