前面一章初步认识了URL,HTTP请求和相应协议格式,有所忘记的可以看一下前面的博客
(3条消息) 【网络篇】第十四篇——HTTP协议(一)(附带电视剧李浔同款爱心+端口号被恶意占用如何清除)_接受平凡 努力出众的博客-CSDN博客
HTTP的方法
HTTP常见的方法有:
方法 | 说明 | 支持的HTTP协议版本 |
GET | 获取资源 | 1.0,1.1 |
POST | 传输实体主体 | 1.0,1.1 |
PUT | 传输文件 | 1.0,1.1 |
HEAD | 获得报文首部 | 1.0,1.1 |
DELETE | 删除文件 | 1.0,1.1 |
OPTIONS | 访问支持的方法 | 1.1 |
TRACE | 追踪路径 | 1.1 |
CONNECT | 要求用隧道协议连接代理 | 1.1 |
LINK | 建立和资源之间的联系 | 1.0 |
UNLINK | 断开连接关系 | 1.0 |
其中最常用的就是GET方法和POST方法。
GET方法和POST方法
GET方法的含义是请求从服务器获取资源, 这个资源可以是文本,页面,图片视频等等。
例如,你打开我在CSDN写的文章,浏览器就会发送GET请求给服务器,服务器就会返回文章的所有文字及资源。
POST方法则是相反的,一般用于将数据上传给服务器,它向URI指定的资源提交数据,数据就放在报文的body中.
例如,你在我的CSDN文章下面,评论了然后提交,浏览器就会执行一次POST请求,把你的评论放进报文body里,然后拼接好POST请求头,通过TCP协议发送给服务器。
GET方法和POST方法都可以带参:
- GET方法是通过url传参的。
- POST方法是通过正文传参的。
从GET方法和POST方法的传参形式可以看出,POST方法能传递更多的参数,因为url的长度是有限制的,而POST方法通过正文传参就可以携带比它更多的数据。
使用POST方法的传参会更加私密,因为POST方法不会将你的参数回显到url当中,此时也就不会被别人轻易看到。不能说POST方法比GET方法更安全,因为POST方法和GET方法实际上都不安全,要做到安全只能通过加密来完成。
GET和POST方法都是安全和幂等的嘛?
先说明下安全和幂等的概念:
- 在 HTTP 协议里,所谓的「安全」是指请求方法不会「破坏」服务器上的资源。
- 所谓的「幂等」,意思是多次执行相同的操作,结果都是「相同」的。
- 那么很明显 GET 方法就是安全且幂等的,因为它是「只读」操作,无论操作多少次,服务器上的数据 都是安全的,且每次的结果都是相同的。
POST 因为是「新增或提交数据」的操作,会修改服务器上的资源,所以是不安全的,且多次提交数据 就会创建多个资源,所以不是幂等的。
Postman演示GET和POST区别
如果访问我们的服务器使用的是GET方法,此时应该通过url进行传参,可以在Params下进行参数设置,因为Postman当中的Params就相当于url当中的参数,你在设置参数时可以看到对应的url也在随之变化。
此时在我们的服务器收到的HTTP请求当中,可以看到请求行中的url就携带上了我们刚才在Postman当中设置的参数。
而如果我们使用的是POST方法,此时就应该通过正文进行传参,可以在Body下进行参数设置,在设置时可以选中Postman当中的raw方式传参,表示原始传参,也就是你输入的参数是什么样的实际传递的参数就是什么样的.
此时服务器收到的HTTP请求的请求正文就不再是空字符串了,而是我们通过正文传递的参数。
因为此时响应正文不为空字符串,因此响应报头当中出现了Content-Length属性,表示响应正文的长度。
TCP套接字演示GET和POST的区别
要演示GET方法和POST方法传参的区别,就需要让浏览器提交参数,此时我们可以在index.html当中再加入两个表单,用作用户名和密码的输入,然后再新增一个提交按钮,此时就可以让浏览器提交参数了。
我们可以通过修改表单当中的method属性指定参数提交的方法,还有一个属性叫做action,表示想把这个表单提交给服务器上的哪个资源。
此时当我们用浏览器访问我们的服务器时,就会显示这两个表单。
当前我们是用GET方法提交参数的,当我们填充完用户名和密码进行提交时,我们的用户名和密码就会自动被同步到url当中。
同时在服务器这边也通过url收到了刚才我们在浏览器提交的参数。
如果我们将提交表单的方法改为POST方法,此时当我们填充完用户名和密码进行提交时,对应提交的参数就不会在url当中体现出来,而会通过正文将这两个参数传递给了服务器。
此时用户名和密码就通过正文的形式传递给服务器了。
说明一下:
使用GET方法时,我们提交的参数会回显到url当中,因此GET方法一般是处理数据不敏感的。
如果你要传递的数据比较私密的话一定要用POST方法,不是因为POST方法安全,实际上GET和POST方法传参都是明文传送,因此都不安全,但是相比于GET而言POST方法更加私密,因为POST是通过正文传参的,不会将参数显示到浏览器上的url框上。
HTTP的状态码
- 1xx类:属于提示信息,是协议处理中的一种中间状态,实际用到的比较少。
- 2xx类:表示服务器成功处理了客户端的请求,也是我们最愿意看到的状态。
「200 OK]是最常见的成功状态码,表示一切正常。如果是非HEAD请求,服务器返回的响应头都会有body数据。
「204 No Content]也是最常见的成功状态码,也200 OK基本相同,但是响应头没有body数据。
[206 Partial Contentt]:是应用于HTTP分块下载或断点续传,表示响应返回的body数据并不是资源的全部,而是其中的一部分,也是服务器处理成功的状态。
- 3xx类:码表示客户端请求的资源发送了变动,需要客户端用新的 URL 重新发送请求获取资源,也就是重定向。
「301 Moved Permanently」表示永久重定向,说明请求的资源已经不存在了,需改用新的URL 再次访问。
「 302 Found 」表示临时重定向,说明请求的资源还在,但暂时需要用另一个 URL 来访问。
301 和 302 都会在响应头里使用字段 Location ,指明后续要跳转的 URL ,浏览器会自动重定向新的 URL。
「304 Not Modified」不具有跳转的含义,表示资源未修改,重定向已存在的缓冲文件,也称缓存重定向,用于缓存控制。
- 4xx类:表示客户端发送的报文有误,服务器无法处理,也就是错误码的含义。
- 「 400 Bad Request 」表示客户端请求的报文有错误,但只是个笼统的错误。
「 403 Forbidden 」表示服务器禁止访问资源,并不是客户端的请求出错。
「 404 Not Found 」表示请求的资源在服务器上不存在或未找到,所以无法提供给客户端。
5xx类:表示客户端请求报文正确,但是服务器处理时内部发生了错误,属于服务器端的错误
码。
「 500 Internal Server Error 」与 400 类型,是个笼统通用的错误码,服务器发生了什么错误,我们并不知道。
「 501 Not Implemented 」表示客户端请求的功能还不支持,类似 “ 即将开业,敬请期待 ” 的意思
「 502 Bad Gateway 」通常是服务器作为网关或代理时返回的错误码,表示服务器自身工作正常,访问后端服务器发生了错误。
「503 Service Unavailable」表示服务器当前很忙,暂时无法响应服务器,类似“网络服务正忙,请稍后重试”的意思。
临时重定向演示
进行临时重定向时需要用到Location字段,Location字段是HTTP报头当中的一个属性信息,该字段表明了你所要重定向到的目标网站。
我们这里要演示临时重定向,可以将HTTP响应当中的状态码改为307,然后跟上对应的状态码描述,此外,还需要在HTTP响应报头当中添加Location字段,这个Location后面跟的就是你需要重定向到的网页,比如我们这里将其设置为CSDN的首页。
#include <iostream> #include <fstream> #include <string> #include <cstring> #include <unistd.h> #include <sys/wait.h> #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <arpa/inet.h> using namespace std; int main() { //创建套接字 int listen_sock = socket(AF_INET, SOCK_STREAM, 0); if (listen_sock < 0){ cerr << "socket error!" << endl; return 1; } //绑定 struct sockaddr_in local; memset(&local, 0, sizeof(local)); local.sin_family = AF_INET; local.sin_port = htons(8081); local.sin_addr.s_addr = htonl(INADDR_ANY); if (bind(listen_sock, (struct sockaddr*)&local, sizeof(local)) < 0){ cerr << "bind error!" << endl; return 2; } //监听 if (listen(listen_sock, 5) < 0){ cerr << "listen error!" << endl; return 3; } //启动服务器 struct sockaddr peer; memset(&peer, 0, sizeof(peer)); socklen_t len = sizeof(peer); for (;;){ int sock = accept(listen_sock, (struct sockaddr*)&peer, &len); if (sock < 0){ cerr << "accept error!" << endl; continue; } if (fork() == 0){ //爸爸进程 close(listen_sock); if (fork() > 0){ //爸爸进程 exit(0); } //孙子进程 char buffer[1024]; recv(sock, buffer, sizeof(buffer), 0); //读取HTTP请求 cout << "--------------------------http request begin--------------------------" << endl; cout << buffer << endl; cout << "---------------------------http request end---------------------------" << endl; //构建HTTP响应 string status_line = "http/1.1 307 Temporary Redirect\n"; //状态行 string response_header = "Location: https://www.csdn.net/\n"; //响应报头 string blank = "\n"; //空行 string response = status_line + response_header + blank; //响应报文 //响应HTTP请求 send(sock, response.c_str(), response.size(), 0); close(sock); exit(0); } //爷爷进程 close(sock); waitpid(-1, nullptr, 0); //等待爸爸进程 } return 0; }
如果我们用浏览器访问我们的服务器,当浏览器收到这个HTTP响应后,还会对这个HTTP响应进行分析,当浏览器识别到状态码是307后就会提取出Location后面的网址,然后继续自动对该网站继续发起请求,此时就完成了页面跳转这样的功能,这样就完成了重定向功能。
此时当浏览器访问我们的服务器时,就会立马跳转到CSDN的首页。
HTTP常见的Header
HTTP常见的Header如下:
- Content-Type:数据类型(text/html等)
- Content-Length:正文的长度。
- Host:客户端告知服务器,所请求的资源是在哪个主机的哪个端口上。
- User-Agent:声明用户的操作系统和浏览器的版本信息。
- Referer:当前页面是哪个页面跳转过来的。
- Location:搭配3XX状态码使用,告诉客户端接下来要去哪里访问。
- Cookie:用于在客户端存储少量信息,通常用于实现会话(session)的功能。
Host:
客户端发送请求时,用来指定服务器的域名。
有了Host字段,就可以将请求发往[同一台]服务器上的不同网站。
Content-Length
服务器在返回数据时,会有Content-Length字段,表明本次回应的数据长度
如上面则是告诉浏览器,本次服务器回应的数据长度是1000个字节,后面的字节就属于下一个回应了。
Connection
Connection 字段最常用于客户端要求服务器使用 TCP 持久连接,以便其他请求复用。
HTTP/1.1 版本的默认连接都是持久连接,但为了兼容老版本的 HTTP ,需要指定 Connection 首部字段的值为 Keep-Alive 。
一个可以复用的 TCP 连接就建立了,直到客户端或服务器主动关闭连接。但是,这不是标准字段。
User-Agent
User-Agent代表的是客户端对应的操作系统和浏览器的版本信息。
比如当我们用电脑下载某些软件时,它会自动向我们展示与我们操作系统相匹配的版本,这实际就是因为我们在向目标网站发起请求的时候,User-Agent字段当中包含了我们的主机信息,此时该网站就会向你推送相匹配的软件版本。
Content-Type
Content-Type 字段用于服务器回应时,告诉客户端,本次数据是什么格式。
上面的类型表明,发送的是网页,而且编码是UTF-8.
客户端请求的时候,可以使用 Accept 字段声明自己可以接受哪些数据格式。 上面代码中,客户端声明自己可以接受任何格式的数据。
Content-Encoding
Content-Encoding 字段说明数据的压缩方法。表示服务器返回的数据使用了什么压缩格式 。
上面表示服务器返回的数据采用了gzip 方式压缩,告知客户端需要用此方式解压。
客户端在请求时,用 Accept-Encoding 字段说明自己可以接受哪些压缩方法。