http协议
1. ip地址
- IP地址分类
- IPv4(由点分十进制组成)
- IPv6(由冒号十六进制组成)
2. http协议
- HTTP协议是一个超文本传输协议,基于TCP传输协议传输数据,规定了浏览器和Web服务器通信数据的格式。
3. URL
- 样子:
http://www.ccblogs.com/home.html?page=1&count=10 - 组成
- 协议部分
- https://,默认端口号443
- http://,默认端口号80
- ftp://
- 域名部分
- www.ccblogs.com
- 资源路径部分
- /home.html
- 查询参数部分
- 可选,?page=1&count=10
- 协议部分
4. 开发者工具推荐
- 谷歌浏览器开发者工具
- Elements(元素,用于查看或修改HTML标签)
- Console(控制台,可以执行js)
- Sources(网页使用的静态资源,比如图片、js、css)
- Network(查看HTTP协议通信过程)
- Header选项
- General(主要信息)
- Response Headers(响应头)
- Request Headers(请求头)
- Response选项查看响应体信息
5. http get请求报文
- HTTP最常见的请求报文
- GET(获取web服务器数据)
- POST(向web服务器提交数据)
- http get请求报文每一行信息后面都用\r\n
- http get请求报文的格式
请求行\r\n
请求头\r\n
空行\r\n - 示例
----http get 请求报文
----请求行----
GET / HTTP/1.1 => 请求方法 请求的资源路径 http协议版本----请求头----
Host: www.ccblogs.com => 服务器的主机IP地址和端口号,如果看不到端口号,默认为80Connection: keep-alive => 和服务端程序保持长连接,当客户端和服务端有一段时间(3~5分钟)没有进行通信,服务端程序会主动向客户端断开连接
Upgrade-Insecure-Requests: 1 => 让客户端请求不安全请求,以后要使用https
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36 => 用户代理,客户端程序名称,可以根据是否有User-Agent来进行反爬虫机制
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,/;q=0.8,application/signed-exchange;v=b3;q=0.9 => 告诉服务端程序可以接受的数据类型
Accept-Encoding: gzip, deflate => 告诉服务端程序支持的压缩算法
Accept-Language: zh-CN,zh;q=0.9 => 告诉服务端程序支持的语言
Cookie:…… => 客户端用户身份的一个标识
----空行----
\r\n
6. http post请求报文
- http post请求报文的格式
请求行\r\n
请求头\r\n
空行\r\n
请求体 - 请求体是浏览器发送给服务器的数据
7. http响应报文
- 对于请求头和响应头,按照客户端与服务端约定好的方式可以进行自定义。
- http响应报文的格式
响应行\r\n
响应头\r\n
空行\r\n
响应体\r\n - 示例
----响应行(状态行)----
HTTP/1.1 200 OK => http协议版本 状态码 状态描述----响应头----
Date: Fri, 03 Jan 2020 07:38:06 GMT => 服务器的时间(格林威治时间,0时区的时间)Connection: Keep-Alive => 和客户端保持长连接
Server: Apache/2.4.39 (cPanel) OpenSSL/1.0.2r mod_bwlimited/1.4 Phusion_Passenger/5.3.7 => 服务器名称
Last-Modified: Wed, 30 Oct 2019 08:19:25 GMT
ETag: “a20086e-2feb-5961c64132659-gzip”
Vary: Accept-Encoding
Content-Encoding: gzip
Content-Length: 2569
Transfer-Encoding: chunked => 服务器发送给客户端程序(浏览器)的数据不确定数据长度,数据发送完成的结束标识:0\r\n,Content-Length: 200(字节),服务器发送给客户端程序的确定数据长度。内容长度这两个选项只能二选一
Content-Type: text/html => 服务器发送给浏览器的内容类型与编码格式
----自定义响应头信息,字节定义响应头的名字和响应头的值。如:is_login: True
Accept-Ranges: bytes----空行----
\r\n----响应体(真正意义上的给浏览器解析的数据)----
网页数据
8. 状态码
- 200(请求成功)
- 307(重定向)
- 400(错误的请求,请求地址或者参数有误)
- 404(请求资源在服务器不存在)
- 500(服务器内部源代码出现错误)
9. python自带静态web服务器搭建
- 静态Web服务器是为发出请求的浏览器提供静态文档的程序
- 搭建Python自带的Web服务器命令
# -m 表示运行包里面的模块,执行命令时要切换到静态文件目录。 python3 -m http.server 端口号
- 端口号未指定,默认8000
10. 静态web服务器 - 返回固定页面
- 示例
import socket # 判断是否为主模块 if __name__ == '__main__': # 创建tcp服务端套接字 tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 设置端口号复用,程序退出端口号立即释放 tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) # 绑定端口号 tcp_server_socket.bind(("", 8000)) # 设置监听 tcp_server_socket.listen(128) while True: # 等待接受客户端的连接请求 new_socket, ip_port = tcp_server_socket.accept() # 接收客户端的请求信息 recv_data = new_socket.recv(4096) # 打开文件,读取文件中的数据 # with open 由系统关闭文件,无需手动关闭 with open("Ccblogs/index.html") as file: file_data = file.read() # 响应行 response_line = "HTTP/1.1 200 OK\r\n" # 响应头 response_header = "Server: ccblogs/1.0\r\n" # 响应体 response_body = file_data # 把数据封装成http响应报文格式的数据 response = response_line + response_header + "\r\n" + response_body # 把字符串编码成二进制 response_data = response.encode("utf-8") # 发送给浏览器的响应报文数据 new_socket.send(response_data) # 关闭服务于客户端的套接字 new_socket.close()
11. 静态web服务器 - 返回指定页面
- 示例
import socket def recv(): # 创建tcp服务端套接字 tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 设置端口号复用,程序退出端口号立即释放 tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) # 绑定端口号 tcp_server_socket.bind(("", 8000)) # 设置监听 tcp_server_socket.listen(128) while True: # 等待接受客户端的连接请求 new_socket, ip_port = tcp_server_socket.accept() # 接收客户端的请求信息 recv_data = new_socket.recv(4096) # 请求数据为空,直接返回 if len(recv_data) == 0: new_socket.close() return # 对数据按照空格进行分割 recv_content = recv_data.decode("utf-8") request_list = recv_content.split(" ", maxsplit=2) # 获取请求的资源路径 request_path = request_list[1] # 判断请求的是否为根目录,若为根目录返回首页 if request_path == "/" : request_path = "/index.html" # 打开文件,读取文件中的数据 # with open 由系统关闭文件,无需手动关闭,使用rb模式,默认兼容二进制文件 with open("Ccblogs" + request_path, "rb") as file: file_data = file.read() # 响应行 response_line = "HTTP/1.1 200 OK\r\n" # 响应头 response_header = "Server: ccblogs/1.0\r\n" # 响应体 response_body = file_data # 把数据封装成http响应报文格式的数据, 把字符串编码成二进制 response = (response_line + response_header + "\r\n").encode("utf-8") + response_body # 发送给浏览器的响应报文数据 new_socket.send(response) # 关闭服务于客户端的套接字 new_socket.close() # 判断是否为主模块 if __name__ == '__main__': recv()
12. 静态web服务器 - 返回404页面
- 示例
import socket def recv(): # 创建tcp服务端套接字 tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 设置端口号复用,程序退出端口号立即释放 tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) # 绑定端口号 tcp_server_socket.bind(("", 8000)) # 设置监听 tcp_server_socket.listen(128) while True: # 等待接受客户端的连接请求 new_socket, ip_port = tcp_server_socket.accept() # 接收客户端的请求信息 recv_data = new_socket.recv(4096) # 请求数据为空,直接返回 if len(recv_data) == 0: new_socket.close() return # 对数据按照空格进行分割 recv_content = recv_data.decode("utf-8") request_list = recv_content.split(" ", maxsplit=2) # 获取请求的资源路径 request_path = request_list[1] # 判断请求的是否为根目录,若为根目录返回首页 if request_path == "/" : request_path = "/index.html" try: # 打开文件,读取文件中的数据 # with open 由系统关闭文件,无需手动关闭,使用rb模式,默认兼容二进制文件 with open("Ccblogs" + request_path, "rb") as file: file_data = file.read() except Exception as e: # 响应行 response_line = "HTTP/1.1 404 Not Found\r\n" # 响应头 response_header = "Server: ccblogs/1.0\r\n" # 打开文件,读取文件中的数据 # with open 由系统关闭文件,无需手动关闭,使用rb模式,默认兼容二进制文件 with open("Ccblogs/error.html", "rb") as file: file_data = file.read() # 响应体 response_body = file_data # 把数据封装成http响应报文格式的数据, 把字符串编码成二进制 response = (response_line + response_header + "\r\n").encode("utf-8") + response_body # 发送给浏览器的响应报文数据 new_socket.send(response) else: # 响应行 response_line = "HTTP/1.1 200 OK\r\n" # 响应头 response_header = "Server: ccblogs/1.0\r\n" # 响应体 response_body = file_data # 把数据封装成http响应报文格式的数据, 把字符串编码成二进制 response = (response_line + response_header + "\r\n").encode("utf-8") + response_body # 发送给浏览器的响应报文数据 new_socket.send(response) finally: # 关闭服务于客户端的套接字 new_socket.close() # 判断是否为主模块 if __name__ == '__main__': recv()