python HTTP协议 HTTP请求报文说明 HTTP 响应报文说明 模仿浏览器请求web服务器 web 服务器

HTTP 协议

1. HTTP 协议简介

  1. http 就是超文本传输协议
  2. 作用: 浏览器和web 服务器之间传输网页资源的协议格式
  3. HTTP底层是基于 TCP 协议实现的, 导致浏览器和服务器之间传输资源之前需要建立连接
  4. HTTP 协议是明文传输, HTTPS 是基于 HTTP 协议的安全通信方式< 密钥交互, 加密, 解密>
  5. web服务器: 提供网页

浏览器访问 web 服务器的通信过程

  1. 通过 DNS (域名解析服务器)将域名解析成 IP 地址
  2. 获取到 IP 地址
  3. 建立连接
  4. 发送 HTTP 请求数据
  5. 根据请求获取资源
  6. 返回资源给 web 服务器
  7. 返回 HTTP 响应数据

2. URL

URL的样子:
https://docs.python.org/3/search.html?q=asyncio&check_keywords=yes&area=default%23xxxx

URL的组成

  1. 协议部分: https:// http:// ftp://
  2. 域名部分: docs.python.org
  3. 查询参数:?q=asyncio&check_keywords=yes&area=default%23
  4. 资源路径:3/search.html
  5. 锚点: xxxx (不是给服务器用的 是给浏览器显示网页的时候用的)

3. HTTP 请求报文说明

3.1 get 请求报文的格式总结:
-- 请求行request line  分为三部分
-- 请求方式method 资源路径 版本
GET / HTTP/1.1
--- 请求方法
--- 	GET  获取 一般用于浏览器从服务器获取资源  <80%>
--- 	POST 提交 一般用于浏览器向服务器提交资源  上传
--- 资源路径<加查询参数>  /表示主页
--  网址是 
https://www.baidu.com/s?wd=haha&rsv_sug4=2068
-- 请求行是 
GET /s?wd=haha&&rsv_sug4=2068 HTTP/1.1
-- 请求头  k:v
# 代表浏览器需要请求的主机名称 一般是域名:非默认端口
Host: www.baidu.com
# 连接方式 keep-alive保持存活-长连接/close-立即关闭-短连接
Connection: keep-alive
# 用户代理 浏览器身份<适配、反爬虫 python3.7>
User-Agent: Mozilla/5.0 (Macintosh;Chrome/79.0.3945.88 
# 接受文件类型
Accept: text/html,application/xhtml+xml..exchange;v=b3;q=0.9
# 接受的文件压缩格式 提高用户体验
Accept-Encoding: gzip, deflate, br
# 接受的语言       简体           英语      繁体
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,zh-TW;q=0.7

get 和 post 的区别:

  1. get 获取少量提交查询参数中 键值对 容易被缓存 因此不安全, 一般没有请求体
  2. post 提交 请求体中任意类型 不被缓存安全 有请求体
3.2 get请求原始报文说明:
GET /index2.html HTTP/1.1\r\n
Host: 127.0.0.1:8888\r\n
Connection: keep-alive\r\n
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8\r\n
Upgrade-Insecure-Requests: 1\r\n
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36\r\n
Accept-Encoding: gzip, deflate, sdch\r\n
Accept-Language: zh-CN,zh;q=0.8\r\n
\r\n
3.3 POST 请求报文说明:
---- 请求⾏ ----
POST /xmweb?host=mail.itcast.cn&_t=1542884567319 HTTP/1.1 # POST请求⽅式 请求资源路径
HTTP协议版本
---- 请求头 ----
Host: mail.itcast.cn # 服务器的主机地址和端⼝号,默认是80
Connection: keep-alive # 和服务端保持⻓连接
Content-Type: application/x-www-form-urlencoded # 告诉服务端请求的数据类型
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHT
ML, like Gecko) Chrome/69.0.3497.100 Safari/537.36 # 客⼾端的名称
---- 空⾏ ----
---- 请求体 ----
username=hello&pass=hello # 请求参数
3.4 POST 请求原始报文说明:
POST /xmweb?host=mail.itcast.cn&_t=1542884567319 HTTP/1.1\r\n
Host: mail.itcast.cn\r\n
Connection: keep-alive\r\n
Content-Type: application/x-www-form-urlencoded\r\n
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHT
ML, like Gecko) Chrome/69.0.3497.100 Safari/537.36\r\n
\r\n(请求头信息后⾯还有⼀个单独的’\r\n’不能省略)
username=hello&pass=hello
3.5 请求报文的格式总结:
  • 请求行[方法 路径 版本\r\n]
  • 请求头[名字: 值\r\n]
  • 空行[\r\n]
  • 请求体[浏览器需要提交给服务器的数据]

需要注意的是:

  • get 方式的请求报文没有请求体, 只有请求行, 请求头, 空行组成
  • post 方式的请求报文可以由请求行, 请求头, 空行, 请求体四部分组成(post 方式可以允许没有请求体, 但是这种格式很少见)

4. HTTP 响应报文格式说明

4.1 响应报文说明:
-- 1. 状态行 status line 分为三步 版本 状态码 状态说明
HTTP/1.1 200 OK
--- 状态码和说明一一对应  HTTP 标准文档规定
--- 1xx 继续  
--- 2xx 成功    200 OK
--- 3xx 重定向   307 Internal Redirect
--- 	Location: https://www.baidu.com/
--- 4xx 客户端错误 404 Not Found
--- 5xx 服务器错误 503 Service Unavailable
-- 2. 响应头  名字:值
-- 连接方式   长连接
Connection: keep-alive
# 内容压缩格式 浏览器通过这个参数知道数据应该怎么解压
Content-Encoding: gzip    
# 内容的长度 
Content-Length : 18
# 内容类型    决定了不同的解析方式
Content-Type: text/html;charset=utf-8
# 日期     响应报文返回的时间  东8区 
Date: Sat, 21 Dec 2019 03:20:13 GMT
# 过期日期   不让浏览器缓存这个网页
Expires: Sat, 21 Dec 2019 03:20:13 GMT
# web服务器名字 Baidu Web Server 
Server: BWS/1.1
4.2 原始响应报文说明:
HTTP/1.1 200 OK\r\n
Server: Tengine\r\n
Content-Type: text/html; charset=UTF-8\r\n
Transfer-Encoding: chunked\r\n
Connection: keep-alive\r\n
Date: Fri, 23 Nov 2018 02:01:05 GMT\r\n
\r\n(响应头信息后⾯还有⼀个单独的’\r\n’不能省略)
<!DOCTYPE html><html lang=“en”></html>
4.3 HTTP 状态码介绍

HTTP 状态码是用于表示 web 服务器相应的 3 位数字代码.

状态码 说明
200 请求成功
307 重定向
400 错误的请求, 请求地址或者参数有误
404 请求资源在服务器不存在
500 服务器内部源代码出现错误
4.4 响应报文格式总结
  • 状态行[版本 状态码 状态说明\r\n]

  • 响应头[名字 : 值\r\n]

  • 空行[\r\n]

  • 响应体[服务器给浏览器发送的数据内容]

5. 模仿浏览器请求web 服务器

验证请求报文和响应报文

import socket

if __name__ == "__main__":
	# 1. 创建一个套接字
	tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
	# 2. 域名解析得到服务器 IP +默认端口 连接服务器
	tcp_socket.connect(("www.baidu.com", 80))
	# 3. 发送请求报文
	http_request_data = "DET/HTTP/1.1\r\n\r\n"
	tcp_socket.send(http_request_data.encode())
	# 4. 得到响应报文
	recv_data = tcp_socket.recv(4096)
	print(recv_data)
	# 5. 关闭套接字
	tcp_socket.close()

6 web 服务器

6.1 返回固定数据
# web 服务器 = TCP服务器+ HTTP 协议
# 1.0 返回固定数据  
import socket

def main():
	# 1 创建一个服务器套接字 绑定 监听转接用户连接请求到和客户端的套接字
	server_socket = socket.socket()
	server_socket.setsockopt(socket.SOL_SOCKET, sock.SO_REUSEADDR, 1)
	server_socket.bind(("", 9999))
	server_socket.listen(128)

	while True:
		 new_client_socket, client_address = server_socket.accept()
		 print("客户端%s 上线了"% str(client_address))
		 # 2. 接受用户请求报文<一个套接字如果没有收数据就关了 那么可能会报错>
		 recv_data = new_client_socket.recv(4096)
		 if not recv_data:
		 	print('客户端%s下线了' % str(client_address))
		 	new_client_socket.close()
		 	continue
		 # 3.回复响应报文< HTTP 响应报文>
		 http_response_data = "HTTP/1.1 200 OK\r\nServer: PWS1.0\r\n\r\n" + "hello world"
		 # 4.关闭套接字和客户端关联的套接字  ----短连接
		 new_client_socket.close()


if __name__ == "__main__":
	main()

浏览器访问 web 服务器效果:
在这里插入图片描述

6.2 返回固定页面
# web 服务器 = TCP服务器+ HTTP 协议
# 1.0 返回固定数据  
# 2.0 返回固定网页或者图片
import socket


def main():
	# 1. 创建一个服务器套接字 绑定 监听转接用户连接请求到和客户端关联的套接字
	server_socket = socket.socket()
	server_socket.setsocketopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
	server_socket.bind(("", 9999))
	server_socket.listen(128)


	while True:
		new_client_socket, client_address = server_socket.accept()
		print("客户端%s上线了" % str(client_address))

		# 2. 接受用户请求报文<一个套接字如果没有收数据就关了, 那么可能会报错>
		recv_data = new_client_socket.recv(4096)
		if not recv_data:
			print("客户端%s下线了" % str(client_address))
			new_client_socket.close()
			continue

		# 打开一个固定文件 读取
		with open("./static/xjj1.jpg", "rb") as file:
			file_data = file.read()

		# 3. 回复响应报文< HTTP 响应报文>
		http_response_data = "HTTP/1.1 200 OK\r\nServer: PWS1.0\r\n\r\n.encode() + file_data"
		new_client_socket.send(http_response_data)

		# 4. 关闭和客户端关联的套接字 - 短链接
		new_client_socket.close()


if __name__ == "__main__":
	main()
			
6.3 返回指定页面
# web 服务器 =TCP 服务器 + HTTP 协议
# 1.0 返回固定数据  
# 2.0 返回固定网页或者图片
import socket

def main():
	# 1. 创建一个服务器套接字 绑定 监听转接用户连接请求到和客户端关联的套接字
	server_socket = socket.socket()
	server_socket.setsockopt(socket.SOL_SOCKET, socket_SO_REUSEADDR, 1)
	server_socket.bind(("", 9999))
	server_socket.listen(128)

	while True:
		new_client_socket, client_address = server_socket.accept()
		print("客户端%s上线了" % str(client_address))
		# 2. 接收用户请求报文<一个套接字如果没有收数据就关了, name可能报错>
		recv_data = new_client_socket.recv(4096)

		# 2.1 判断用户是否已经下线
		if not recv_data:
			print(" 客户端%s 已经下线了) % str(client_address))
			new_client_socket.close()
			continue
		
		# 2.2 获取到用户请求报文中的资源路径
		path_info = recv_data.decode().split(" ")[1]
		print("收到用户的资源请求路径是," path_info)

		# 2.3 判断如果用户请求路径是否为空 /
		if path_info == "/":
			patn_info = "/grand.html"
			
		# 2.4 打开一个指定文件读取
		try:
			# 可能发生异常的代码 执行这里
			with open("./static/404.html", "rb") as file:
				file_data = file.read()
		except Exception as e:
			# 如果发生异常 执行这里
			with open("./static/404.html", "rb") as file:
				file_data = file.read()
			http_response_data = "HTTP/1.1 404 Not Found\r\nServer: PWS1.0\r\n\r\n".encode() + file_data
		else:
			# 没有异常执行这里
			# 3. 回复响应报文<HTTP 响应报文>
			http_response_data = "HTTP/1.1 200 OK\r\nServer: PWS1.0\r\n\r\n".encode() + file_data
			
		finally:
			# 不管有没有异常 都执行这里
			new_client_socket.send(http_response_data)
			# 4. 关闭和客户端关联的套接字 ---短连接
			new_client_socket.close()


if __name__ == "__main__":
	main()

未完待续 接下篇

HTTP协议 web服务器多任务版 , 面向对象版, 命令行参数指定 web 服务器端口

发布了56 篇原创文章 · 获赞 17 · 访问量 2143

猜你喜欢

转载自blog.csdn.net/LanlanDeming/article/details/103705211