文章目录
- 应用层HTTP协议
- 1、HTTP协议概念
- 2、URL(统一资源定位符)
- 2.1、URL的encode(编码)和decode(解码)
- 3、HTTP请求和响应报头格式
- 3.1、请求报头
- 3.2、响应报头
- 4、HTTP的方法
- 4.1、GET方法
- 4.2、POST方法
- 4.3、HEAD方法
- 5、HTTP状态码
- 6、HTTP常见报头类型
- 7、简单的HTTP服务器
应用层HTTP协议
1、HTTP协议概念
在前面的博客中我们有提到网络版计算器,其中
Calculate.hpp
文件就是应用层,也就是我们程序员需要做的一些功能,Protocol.hpp
文件并不是应用层协议,而是我们的自定义的表示层(负责数据格式转换、加密解密)。而HTTP(HyperText Transfer Protocol,超文本传输协议)是一个至关重要的协议。它定义了客户端(如浏览器)与服务器之间如何通信,以交换或传输超文本(如 HTML 文档)。HTTP 协议是客户端与服务器之间通信的基础。客户端通过 HTTP 协议向服务器发送请求,服务器收到请求后处理并返回响应。HTTP 协议是一个无连接、无状态的协议,即每次请求都需要建立新的连接(HTTP/1.1不需要),且服务器不会保存客户端的状态信息。
2、URL(统一资源定位符)
我们平时访问的网址其实就是URL。
小知识,一般域名就是IP地址。
我们可以看到,这里域名加端口就是IP+端口,可以唯一确定互联网上的一台主机或服务器。
注意,在路径那里,
/
不一定表示的是根目录,可能是当前代码的一个文件夹目录,比如./wwwroot
,现在不懂,在后面的代码实现里面就懂了。
2.1、URL的encode(编码)和decode(解码)
像
/?:
等这样的字符,已经被 url 当做特殊意义理解了。因此这些字符不能随意出现。比如,某个参数中需要带有这些特殊字符,就必须先对特殊字符进行转义。
转义的规则如下:
将需要转码的字符转为 16 进制,然后从右到左,取 4 位(不足 4 位直接处理),每 2 位做一位,前面加上%,编码成%XY 格式。
可以看到,
+
被编码成为了%2B
。解码的规则就是编码规则的逆向。
编码和解码
3、HTTP请求和响应报头格式
3.1、请求报头
从上图可以看出,请求报头涵盖请求行、请求报头、空行和请求正文。
请求行:[方法] + [url] + [版本]
请求报头:请求的属性,冒号分割的键值对,每组属性之间使用
\r\n
分隔,遇到空行表示当前请求报头部分结束。正文:空行后面的内容都是正文,正文允许为空字符串。如果正文存在,则在请求行会有一个Conten-Length属性的字段来标识正文的长度。
代码显示请求报头字段:
3.2、响应报头
从上图可以看出,请求报头涵盖状态行、响应报头、空行和响应正文。
状态行:[版本号] + [状态码] + [状态码解释]
响应报头:响应的属性,冒号分割的键值对,每组属性之间使用
\r\n
分隔,遇到空行表示当前响应报头部分结束正文:空行后面的内容都是正文。正文允许为空字符串,如果正文存在,则在正文中会有一个
Content-Length
属性来标识 正文的长度,如果服务器返回了一个 html 页面,那么 html 页面内容就是在正文中。程序显示响应报头字段:注意,这里没有打印正文部分,因为当以二进制格式打开文件的时候,正文部分拿到是二进制,显示的字符我们看不懂。这里选择不打印。
4、HTTP的方法
HTTP 方法 描述 GET 请求指定的资源。仅用于请求数据,不对资源进行修改。 POST 向服务器提交数据进行处理(例如提交表单或者上传文件)。数据包含在请求体中。 PUT 请求服务器存储一个资源,并用请求体中的数据替代指定的资源(完全替代)。 DELETE 请求服务器删除指定的资源。 HEAD 类似于GET请求,只不过返回的响应中没有具体内容,用于获取报头。 OPTIONS 返回服务器支持的HTTP方法。可以用于检查服务器的功能。 PATCH 用于局部更新资源。只传递需要修改的数据,而不是整个资源。 CONNECT 建立一个到目标资源的隧道。主要用于代理服务器将HTTPS请求传到目的服务器。 TRACE 回显服务器收到的请求,主要用于测试或诊断。 常用的方法是:GET和POST
4.1、GET方法
用途:用于请求 URL 指定的资源。
示例:GET /index.html HTTP/1.1
特性:指定资源经服务器端解析后返回响应内容。
form 表单:https://www.runoob.com/html/html-forms.html
这里的method方法的post改为get(大小写忽略),就是请求时用的GET方法。
GET方法如果在提交时,有参数需要提交的话,会把参数放在url中。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>About Us</title> </head> <body> <header> <h1>About Us</h1> <nav> <ul> <li><a href="index.html">Home</a></li> <li><a href="about.html">About</a></li> <li><a href="contact.html">Contact</a></li> </ul> </nav> </header> <!-- get把账号密码放url,post放正文 --> <form action="/login" method="get" <label for="username">用户名:</label><br> <input type="text" id="username" name="username" required><br><br> <label for="password">密码:</label><br> <input type="password" id="password" name="password" required><br><br> <input type="submit" value="提交"> </form> <main> <section> <h2>Our Story</h2> <p>We are a company dedicated to providing the best service possible. Our journey started in...</p> </section> <section> <h2>Our Team</h2> <p>Meet the wonderful people behind our success...</p> </section> </main> <footer> <p>© 2024 Your Name. All rights reserved.</p> </footer> <img src="/Image/2.png" alt="test"> </body> </html>
Fiddler抓包:可以看到账号密码是在url中。
4.2、POST方法
用途:用于传输实体的主体,通常用于提交表单数据。
示例:GET /index.html HTTP/1.1
特性:可以发送大量的数据给服务器,并且数据包含在请求体中。
form 表单:https://www.runoob.com/html/html-forms
POST方法如果在提交时,有参数需要提交的话,会把参数放在正文中。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>About Us</title> </head> <body> <header> <h1>About Us</h1> <nav> <ul> <li><a href="index.html">Home</a></li> <li><a href="about.html">About</a></li> <li><a href="contact.html">Contact</a></li> </ul> </nav> </header> <!-- get把账号密码放url,post放正文 --> <form action="/login" method="post" <label for="username">用户名:</label><br> <input type="text" id="username" name="username" required><br><br> <label for="password">密码:</label><br> <input type="password" id="password" name="password" required><br><br> <input type="submit" value="提交"> </form> <main> <section> <h2>Our Story</h2> <p>We are a company dedicated to providing the best service possible. Our journey started in...</p> </section> <section> <h2>Our Team</h2> <p>Meet the wonderful people behind our success...</p> </section> </main> <footer> <p>© 2024 Your Name. All rights reserved.</p> </footer> <img src="/Image/2.png" alt="test"> </body> </html>
Fiddler抓包:可以看到账号密码(提交的参数)在正文部分!
4.3、HEAD方法
用途:与 GET 方法类似,但不返回报文主体部分,仅返回响应头。
示例:HEAD /index.html HTTP/1.1
特性:用于确认 URL 的有效性及资源更新的日期时间等。
预备知识:
curl
是一个命令行工具,用于传输数据,支持多种协议,包括 HTTP、HTTPS、FTP 等。它常用于测试或自动化脚本中,以发送请求到服务器并接收响应。当你使用curl -i www.baidu.com
命令时,你实际上是在尝试通过 HTTP 协议向www.baidu.com
发送一个 GET 请求,并希望获取响应的头部信息(headers)以及可能的响应体(body)。--head
就是只获取响应头,-i
就是--include
。默认情况下(不加选项),curl
只显示响应体,不包括头部。xp2@VM-8-12-ubuntu:~$ curl --head www.baidu.com HTTP/1.1 200 OK Accept-Ranges: bytes Cache-Control: private, no-cache, no-store, proxy-revalidate, no-transform Connection: keep-alive Content-Length: 277 Content-Type: text/html Date: Thu, 08 Aug 2024 03:04:49 GMT Etag: "575e1f71-115" Last-Modified: Mon, 13 Jun 2016 02:50:25 GMT Pragma: no-cache Server: bfe/1.0.8.18 xp2@VM-8-12-ubuntu:~$
5、HTTP状态码
状态码 原因短语 类别 1XX 接收的请求正在处理 Informational (信息性状态码) 2XX 请求正常处理完毕 Success (成功状态码) 3XX 需要进行附加操作以完成请求 Redirection (重定向状态码) 4XX 服务器无法处理请求 Client Error (客户端错误状态码) 5XX 服务器处理请求出错 Server Error (服务器错误状态码) 常见的状态码及含义描述:
状态码 含义 应用样例 100 Continue 上传大文件时,服务器告诉客户端可以继续上传 101 Switching Protocols 服务器同意客户端更改协议 200 OK 访问网站首页,服务器返回网页内容 201 Created 发布新文章,服务器返回文章创建成功的信息 202 Accepted 服务器已接受请求,但尚未处理 203 Non-Authoritative Information 服务器已成功处理请求,但返回的信息可能来自另一来源 204 No Content 删除文章后,服务器返回“无内容”表示操作成功 205 Reset Content 服务器处理成功,用户代理应重置文档视图 206 Partial Content 服务器成功处理了部分 GET 请求 300 Multiple Choices 多种选择,用户或用户代理可以自行选择 301 Moved Permanently 网站换域名后,自动跳转到新域名;搜索引擎更新新网站链接时使用 302 Found 临时重定向,要求客户端执行临时重定向 303 See Other 客户端应使用 GET 方法获取资源 304 Not Modified 缓存的资源未修改,客户端可继续使用 305 Use Proxy 资源必须通过代理访问 307 Temporary Redirect 临时重定向,要求客户端保持请求方法和主体 400 Bad Request 请求语法错误,服务器无法理解 401 Unauthorized 请求要求用户身份验证 403 Forbidden 服务器理解请求,但拒绝执行 404 Not Found 服务器找不到请求的资源 405 Method Not Allowed 请求方法不被允许 406 Not Acceptable 服务器无法根据客户端请求的内容特性完成请求 407 Proxy Authentication Required 请求要求代理身份验证 408 Request Timeout 服务器等待客户端发送的请求时间过长 409 Conflict 服务器在完成请求时发生冲突 410 Gone 请求的资源已被永久删除 411 Length Required 服务器要求在请求中包含内容长度 412 Precondition Failed 服务器未满足请求的前提条件 413 Payload Too Large 请求实体过大,服务器无法处理 414 URI Too Long 请求的 URI 过长,服务器无法处理 415 Unsupported Media Type 请求的媒体格式不受支持 416 Range Not Satisfiable 请求的范围无法满足 417 Expectation Failed 服务器未满足 “Expect” 请求标头字段的要求 500 Internal Server Error 服务器内部错误 501 Not Implemented 服务器不支持请求的方法 502 Bad Gateway 服务器作为网关或代理时收到无效响应 503 Service Unavailable 服务器目前无法处理请求(由于超载或停机维护) 504 Gateway Timeout 服务器作为网关或代理,未及时从上游服务器收到响应 505 HTTP Version Not Supported 服务器不支持请求的 HTTP 版本 关于重定向:
HTTP 状态码 301(永久重定向)和 302(临时重定向)都依赖 Location 选项。以下是关于两者依赖 Location 选项的详细说明:
HTTP 状态码 301(永久重定向):
当服务器返回 HTTP 301 状态码时,表示请求的资源已经被永久移动到新的位置。
在这种情况下,服务器会在响应中添加一个 Location 头部,用于指定资源的新位置。这个 Location 头部包含了新的 URL 地址,浏览器会自动重定向到该地址。
例如,在 HTTP 响应中,可能会看到类似于以下的头部信息:
HTTP/1.0 301 Moved Permanently: This and all future requests should be directed to the given URI. Connection: keep-alive Content-Type: Keep-Alive: timeout=4 Location: http://129.204.171.204:8888/Image/2.png Proxy-Connection: keep-alive
HTTP 状态码 302(临时重定向):
当服务器返回 HTTP 302 状态码时,表示请求的资源临时被移动到新的位置。
同样地,服务器也会在响应中添加一个 Location 头部来指定资源的新位置。浏览器会暂时使用新的 URL 进行后续的请求,但不会缓存这个重定向。
例如,在 HTTP 响应中,可能会看到类似于以下的头部信息:
HTTP/1.0 302 Found: Tells the client to look at (browse to) another URL. Connection: keep-alive Content-Type: Keep-Alive: timeout=4 Location: http://129.204.171.204:8888/Image/2.png Proxy-Connection: keep-alive
总结:无论是 HTTP 301 还是 HTTP 302 重定向,都需要依赖 Location 选项来指定资源的新位置。这个 Location 选项是一个标准的 HTTP 响应头部,用于告诉浏览器应该将请求重定向到哪个新的 URL 地址。
6、HTTP常见报头类型
字段名 含义 样例 Content-Type
资源的MIME类型(例如,文本、HTML、JPEG图片等) Content-Type: text/html; charset=utf-8
Content-Length
请求体(body)的字节大小 Content-Length: 348
User-Agent
发起请求的客户端(如浏览器)信息 User-Agent: Mozilla/5.0 (Windows NT 10.0; ...)
Accept
客户端可接受的响应内容类型(如HTML、JSON等) Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Authorization
客户端身份验证信息(如Basic认证或Token) Authorization: Basic QWxhZGRpbjpvcGVuU2VzYW1l
Cookie
存储在客户端的键值对数据,服务器可用于追踪用户会话等 Cookie: sessionToken=abc123; user=johndoe
Set-Cookie
服务器发送到客户端的Cookie信息,用于创建或更新Cookie Set-Cookie: sessionToken=abc123; Path=/; HttpOnly
Cache-Control
指示请求/响应消息体是否应被缓存、何时可以缓存等策略 Cache-Control: max-age=600, public
Location
重定向的目标URL(主要用于3xx响应) Location: http://example.com/new-page.html
Referer
指示当前请求页面的前一个页面的URL(如果存在) Referer: http://example.com/some-page.html
Connection
指示是否需要保持连接(keep-alive)或关闭(close) Connection: keep-alive
Host
请求的资源所在的服务器主机名和端口号(如果非标准端口) Host: www.example.com
Date
消息发送的日期和时间(RFC 7231 格式) Date: Tue, 15 Nov 1994 08:12:31 GMT
Content-Encoding
对实体主体内容采用的编码类型(如gzip、deflate等) Content-Encoding: gzip
Server
处理请求的服务器软件名称和版本号(如Apache/2.4.41) Server: Apache/2.4.41 (Unix)
7、简单的HTTP服务器
下面代码基本融合了上面所有所涉及的核心知识。
因为代码里面存在相对路径,还有文件夹,防止路径错误请自行下载,代码放在这里了:HTTP服务器
运行结果:
OKOK,应用层HTTP协议就到这里,如果你对Linux和C++也感兴趣的话,可以看看我的主页哦。下面是我的github主页,里面记录了我的学习代码和leetcode的一些题的题解,有兴趣的可以看看。
Xpccccc的github主页