文章目录
HTTP协议
虽然我们说,应⽤层协议是我们程序猿⾃⼰定的.但实际上,已经有⼤佬们定义了⼀些现成的,⼜⾮常好
⽤的应⽤层协议,供我们直接参考使⽤.HTTP(超⽂本传输协议)就是其中之⼀。
在互联⽹世界中,HTTP(HyperText Transfer Protocol,超⽂本传输协议)是⼀个⾄关重要的协议。
它定义了客⼾端(如浏览器)与服务器之间如何通信,以交换或传输超⽂本(如HTML⽂档)。
- HTTP协议是客⼾端与服务器之间通信的基础。
- 客⼾端通过HTTP协议向服务器发送请求,服务器收到请求后处理并返回响应。
- HTTP协议是⼀个
⽆连接、⽆状态
的协议,即每次请求都需要建⽴新的连接,且服务器不会保存客⼾端的状态信息
认识URL
平时我们俗称的"⽹址"其实就是说的URL
urlencode和urldecode
像/ ? :等这样的字符,已经被 url 当做特殊意义理解了.因此这些字符不能随意出现.
⽐如,某个参数中需要带有这些特殊字符,就必须先对特殊字符进⾏转义.
转义的规则如下:
将需要转码的字符转为16进制,然后从右到左,取4位(不⾜4位直接处理),每2位做⼀位,前⾯加
上%,编码成%XY格式
例如:
“+“被转义成了”%2B”
urldecode就是urlencode的逆过程;
urllencode工具
HTTP协议请求与响应格式
HTTP请求
- ⾸⾏: [⽅法] + [url] + [版本]
- Header:请求的属性,冒号分割的键值对;每组属性之间使⽤ \r\n 分隔;遇到空⾏表⽰ Header
部分结束 - Body:空⾏后⾯的内容都是Body.Body允许为空字符串.如果Body存在,则在Header中会有⼀个
Content-Length属性来标识Body的⻓度;
HTTP响应
- ⾸⾏: [版本号] + [状态码] + [状态码解释]
- Header: 请求的属性,冒号分割的键值对;每组属性之间使⽤\r\n分隔;遇到空⾏表⽰Header部分结
束 - Body:空⾏后⾯的内容都是Body.Body允许为空字符串.如果Body存在,则在Header中会有⼀个
Content-Length属性来标识Body的⻓度;如果服务器返回了⼀个html⻚⾯,那么html⻚⾯内容就
是在body中.
HTTP的⽅法
其中最常⽤的就是GET⽅法和POST⽅法
GET⽅法
⽤途:⽤于请求URL指定的资源。
⽰例: GET /index.html HTTP/1.1
特性:指定资源经服务器端解析后返回响应内容。
POST⽅法
⽤途:⽤于传输实体的主体,通常⽤于提交表单数据。
⽰例: POST /submit.cgi HTTP/1.1
特性:可以发送⼤量的数据给服务器,并且数据包含在请求体中
PUT⽅法
⽤途:⽤于传输⽂件,将请求报⽂主体中的⽂件保存到请求URL指定的位置。
⽰例: PUT /example.html HTTP/1.1
特性:不太常⽤,但在某些情况下,如RESTful API中,⽤于更新资源。
HEAD⽅法
⽤途:与GET⽅法类似,但不返回报⽂主体部分,仅返回响应头。
⽰例: HEAD /index.html HTTP/1.1
特性:⽤于确认URL的有效性及资源更新的⽇期时间等。
DELETE⽅法
⽤途:⽤于删除⽂件,是PUT的相反⽅法。
⽰例: DELETE /example.html HTTP/1.1
特性:按请求URL删除指定的资源。
OPTIONS⽅法
⽤途:⽤于查询针对请求URL指定的资源⽀持的⽅法。
⽰例: OPTIONS * HTTP/1.1
特性:返回允许的⽅法,如GET、POST等。
HTTP的状态码
最常⻅的状态码,⽐如 200(OK), 404(Not Found), 403(Forbidden), 302(Redirect,重定向),504(Bad
Gateway)
关于重定向的验证,以301为代表
HTTP状态码301(永久重定向)和302(临时重定向)都依赖Location选项。以下是关于两者依赖
Location选项的详细说明:
HTTP状态码301(永久重定向)
- 当服务器返 HTTP 301状态码时,表⽰请求的资源已经被永久移动到新的位置。
- 在这种情况下,服务器会在响应中添加⼀个Location头部,⽤于指定资源的新位置。这个Location
头部包含了新的URL地址,浏览器会⾃动重定向到该地址。
例如,在HTTP响应中,可能会看到类似于以下的头部信息:
HTTP/1.1 301 Moved Permanently\r\n
Location: https://www.new-url.com\r\n
HTTP状态码302(临时重定向)
- 当服务器返回 HTTP 302状态码时,表⽰请求的资源临时被移动到新的位置。
- 同样地,服务器也会在响应中添加⼀个Location头部来指定资源的新位置。浏览器会暂时使⽤新的
URL进⾏后续的请求,但不会缓存这个重定向。
例如,在HTTP响应中,可能会看到类似于以下的头部信息:
HTTP/1.1 302 Found\r\n
Location: https://www.new-url.com\r\n
总结:⽆论是HTTP 301还是HTTP 302重定向,都需要依赖Location选项来指定资源的新位置。
这个Location选项是⼀个标准的HTTP响应头部,⽤于告诉浏览器应该将请求重定向到哪个新的URL地址。
HTTP常⻅Header
- Content-Type: 数据类型(text/html等)
- Content-Length: Body的⻓度
- Host: 客⼾端告知服务器, 所请求的资源是在哪个主机的哪个端⼝上;
- User-Agent: 声明⽤⼾的操作系统和浏览器版本信息;
- Referer: 当前⻚⾯是从哪个⻚⾯跳转过来的;
- Location: 搭配3xx状态码使⽤, 告诉客⼾端接下来要去哪⾥访问;
- Cookie: ⽤于在客⼾端存储少量信息. 通常⽤于实现会话(session)的功能;
关于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的表格
最简单的HTTP服务器
实现⼀个最简单的HTTP服务器,只在⽹⻚上输出"hello world";只要我们按照HTTP协议的要求构造数
据,就很容易能做到
#include <iostream>
#include <sys/socket.h>
#include <netinet/in.h>
#include <strings.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#define default_backlog 5
int main(int argc, char* argv[])
{
if(argc != 3)
{
std::cout << "Usage " << argv[0] << " ip port" << std::endl;
exit(1);
}
int sock = socket(AF_INET, SOCK_STREAM, 0);
if(sock < 0)
exit(1);
std::string ip = argv[1];
uint16_t port = std::stoi(argv[2]);
sockaddr_in addr;
bzero(&addr, sizeof(addr));
addr.sin_addr.s_addr = inet_addr(ip.c_str());
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
int b = bind(sock, (const sockaddr*)&addr, sizeof(addr));
if(b < 0)
exit(1);
int l = listen(sock, default_backlog);
if(l < 0)
exit(1);
while(true)
{
sockaddr_in client_addr;
socklen_t len;
int sockfd = accept(sock, (sockaddr*)&client_addr, &len);
if(sockfd < 0)
continue;
char input_buffer[5120] = { 0 };
int r = read(sockfd, input_buffer, sizeof(input_buffer) - 1);
if(r < 0)
return 1;
std::cout << "[Request] " << input_buffer << std::endl;
char buffer[1024] = { 0 };
const char* hello = "<h1>Hello World</h1>";
sprintf(buffer, "HTTP /1.0 200 OK\nContent-Length: %lu\n\n%s", strlen(hello), hello);
write(sockfd, buffer, sizeof(buffer));
}
return 0;
}
此处我们使⽤8081端⼝号启动了HTTP服务器.虽然HTTP服务器⼀般使⽤80端⼝,
但这只是⼀个通⽤的习惯.并不是说HTTP服务器就不能使⽤其他的端⼝号.
favicon.ico 是⼀个⽹站图标,通常显⽰在浏览器的标签⻚上、地址栏旁边或收藏夹中。
这个图标的⽂件名favicon 是"favorite icon" 的缩写,⽽ .ico 是图标的⽂件格式。
浏览器在发起请求的时候,也会为了获取图标⽽专⻔构建http请求,我们不管它。