【计算机网络】—— 面试常问的协议之HTTP篇

认识URI和URL

  • URI称为统一资源标识符,URL称为统一资源定位符
  • URI用字符串来标识某一个互联网的资源,而URL表示资源所处的地址,因此URL是URI的子集

平时我们俗称的"网址"就是我们现在要认识的URL
URL

  • 使用http:或者https:等协议方案名获取资源时一定要指定协议的类型
  • 登录信息:指定用户名和密码作为从服务器端获取资源时必要的登录信息(身份认证),可选项
  • 服务器地址:使用绝对的URI必须指定待访问的服务器地址,地址可以时xxxx.jp这种能够被DNS解析的名称,或是192.168.1.1这类IPv4地址名,或是IPv6地址名
  • 服务器端口号:指定服务器连接的网络端口号,可选择项,用户忽略时为默认端口号
  • 带层次的文件路径:指定服务器上的文件路径来定位要访问的特定资源,这与我们学习的Linux文件目录类似
  • 查询字符:针对一指定的文件路径中的资源,可使用查询字符串传入任意参数。可选项
  • 片段标识符:使用片段标识符通常可以标记出以获取资源中的子资源(文档内的某个位置)

HTTP协议格式

用于HTTP协议交互的信息称为HTTP报文,请求端的报文称为HTTP请求,响应端的报文称为HTTP响应,HTTP报文由报文首部+空行+报文主体组成,其中报文主体并不一定要有。
HTTP报文结构

HTTP请求
  • HTTP请求的结构
    HTTP请求结构
  • HTTP请求的具体内容
    HTTP请求的内容
HTTP响应
  • HTTP响应的结构
    HTTP响应结构
  • HTTP响应具体内容
    HTTP响应
HTTP的方法

HTTP方法

GET方法与POST方法的区别(灰常重要)
(一)从HTTP报文来看
  • GET请求方式:将请求信息放在URL后面,请求信息和URL之间以?隔开,请求信息的格式为键值对,例如 https://baike.baidu.com/item/Python/407313?fr=aladdin,这种请求方式将请求信息直接暴露在URL中,安全性较低。另外从报文结构上来看,由于请求信息放置在URL中,因此请求报文中不需要报文主体。
  • POST请求方式:将请求信息放置在报文主体中,想获得请求信息必须解析报文,因此安全性较GET方式要高一些(事实上要获得报文体中的请求信息也是很容易的,因此安全性上两者并没有太多的区别,具体解决传输过程中的安全性问题还要靠HTTPS),此外在请求报文中含有报文体。
  • 由于GET中的请求信息放置在URL中,因此是有长度限制的,因为URL本身是有长度限制的。
  • POST中的请求信息是放置在报文体中,因此对数据长度是没有限制的。
(二)从数据库层面来看
  • GET请求方式符合幂等性和安全性(幂等性的定义:对数据库的一次操作和多次操作获得的结果是一致的,则认为符合幂等性。安全性的定义:对数据库的操作没有改变数据库中的数据,则认为符合安全性),GET请求方式是做查询操作,因此不会改变数据库中原有的数据,认为符合安全性。事实上GET请求可能会出现多次请求的结果(例如在两次请求中间对数据库中的数据作了更改),从这来说是不符合幂等性的定义,但是因为GET请求知识查询数据库,不会对数据库做任何更改,因此也认为是幂等的。
  • POST请求方式是既不幂等又不安全,首先POST请求方式往数据库中提交数据的,因此会改变数据库中的数据。其次,POST请求方式每次获得的结果都有可能不一样,因为POST请求是作用在上一级的URL上的,则每一次请求都会添加一份新资源(这也是POST和PUT方式的最大区别,PUT方式是幂等的)。

注意:在这里提到的安全性和上一部分提到的安全性不是同一概念,不要混淆。

(三)从其他层面来看
  • GET请求能够被缓存。
  • GET请求会保存在浏览器的浏览记录中。
  • 以GET请求的URL能够保存为浏览器书签。

而POST方式都不具备上述功能。缓存也是GET请求被广泛应用的根本,在现代网络上每天产生的请求数目是巨大地,并且其中绝大部分请求均为只读请求,如果所有这些请求都要交由 Web 服务器直接处理,这无疑是巨大的资源浪费。从第二部分知道GET表达的是一种幂等的、安全的,它除了返回结果不应该会产生其它副作用,因此绝大部分GET请求(通常超过90%)都直接被CDN缓存了,这能大大减少 Web 服务器的负担。 而POST是非幂等的,有副作用的操作,所以必须交由 Web 服务器处理。

HTTP状态码

状态码

2XX 成功
  • 200 OK,表示从客户端传递的消息已被服务器正常处理了
  • 204 No Content,表示服务器接收到请求并成功处理,但并未返回任何资源,即响应报文不含实体的主体部分。
  • 206 Partial Content,表示客户端进行了范围请求,服务器成功处理该请求
3XX 重定向
  • 301 Moved Permanently,永久性重定向。表示请求的资源以及被分配了新的URI,以后应使用资源现在所指的URL来访问该资源。
  • 302 Found,临时性重定向。表示请求的资源被分配了新的URI,希望用户(本次)能够用新的URI访问该资源。
  • 303 See Other,表示请求对应的资源存在另一个URI,应使用GET方法定向或得请求的资源

注:301,302,303响应码返回是,几乎所有浏览器都会将POST请求转换为GET请求,并删除请求报文内的主体,再次发送请求,虽然标准要求不能将POST转换为GET,但是一般都会这么做

  • 304 Not Modified,表示用户发送的是附带条件的请求,服务器允许请求访问资源,但是未满足客户端条件的情况下,返回304状态码
  • 307 Temporary Redirect,临时重定向。与302有相同的含义,但是该状态码会遵照浏览器的标准不会将POST转换为GET
4XX 客户端错误
  • 400 Bad Request,表示请求报文中存在语法错误,错误发生后需要修改内容后重新发送
  • 401 Unauthorized,表示请求需要有通过HTTP认证(BASIC认证、DIGEST认证)的认证信息,若之前已经返回过一次401状态码了,则表示用户认证失败
  • 403 Forbidden,表示对请求的资源的访问被服务器拒绝了,服务器可选择是否给出拒绝的原因(可能为未获得文件系统的访问授权,访问权限出现了问题等)
  • 404 Not Found,表示服务器无法找到请求的资源,也可用在服务器拒绝请求并且不想给出原因的时候
5XX 服务器错误
  • 500 Internal Server Error,表示服务器在执行请求时发生了错误,也有可能是Web应用存在的bug或是某些临时的故障
  • 503 Service Unavailable,表示服务器暂时处在超负载或者正在进行停机维护,现在无法处理请求,如果事先已经知道解除该状态的时间,最好写入Retry-After首部字段中返回给客户端让其知晓什么时候可以再次访问服务器

注:有时候状态码和状况可能会出现不一致的情况,可能服务器出现了处理错误,却仍旧返回一个200 OK的状态码给用户

简单的HTTP服务器
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

void Usage() {
	printf("usage: ./server [ip] [port]\n");
}
int main(int argc, char* argv[]) {
	 if (argc != 3) {
		 Usage();
		 return 1;
	 }
	 int fd = socket(AF_INET, SOCK_STREAM, 0);
	 if (fd < 0) {
		 perror("socket");
		 return 1;
	 }
	 struct sockaddr_in addr;
	 addr.sin_family = AF_INET;
	 addr.sin_addr.s_addr = inet_addr(argv[1]);
	 addr.sin_port = htons(atoi(argv[2]));
	 int ret = bind(fd, (struct sockaddr*)&addr, sizeof(addr));
	 if (ret < 0) {
		 perror("bind");
		 return 1;
	 }
	 ret = listen(fd, 10);
	 if (ret < 0) {
		 perror("listen");
		 return 1;
	 }
	 for (;;) {
		 struct sockaddr_in client_addr;
		 socklen_t len;
		 int client_fd = accept(fd, (struct sockaddr*)&client_addr, &len);
		 if (client_fd < 0) {
			 perror("accept");
			 continue;
		 }
		 char input_buf[1024 * 10] = {0}; // 用一个足够大的缓冲区直接把数据读完.
		 ssize_t read_size = read(client_fd, input_buf, sizeof(input_buf) - 1);
		 if (read_size < 0) {
			 return 1;
		 }
		 printf("[Request] %s", input_buf);
		 char buf[1024] = {0};
		 //创建一个html界面返回给客户端
		 const char* hello = "<h1>hello world</h1>";
		 sprintf(buf, "HTTP/1.0 200 OK\nContent-Length:%lu\n\n%s", strlen(hello), hello);
		 write(client_fd, buf, strlen(buf));
	 }
	 return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值