http协议和web服务器
HTTP 协议与简易 Web 服务器开发笔记(补充版)
一、HTTP 协议概述
1. TCP 协议
- 是大多数网络应用之间通信的底层协议。
- 提供可靠的点对点连接,确保数据包按序到达。
2. HTTP 协议的作用
- 特指浏览器和服务器之间的数据通信格式。
- 规定了浏览器与服务器之间
send
和recv
数据的具体格式。
二、URL 结构解析
一个完整的 URL 包括以下三部分:
部分 | 示例 |
---|---|
协议部分 | https:// , http:// , ftp:// |
域名部分 | news.163.com |
资源路径部分 | /18/1122/10/E178J2O4000189FH.html |
三、HTTP 请求报文格式
1. 请求行(Request Line)
- 格式:
请求方法 请求资源路径 HTTP版本
- 示例:
GET /index.html HTTP/1.1
2. 请求头(Request Headers)
- 每一行是一个键值对,如:
Host: www.example.com User-Agent: Mozilla/5.0
- 多个头部之间以
\r\n
分隔。
3. 空行(Empty Line)
- 表示请求头结束,后面是请求体(GET 没有请求体)。
4. 请求体(Request Body)
- 用于 POST 请求提交的数据,如:
name=Tom&age=20
四、HTTP 响应报文格式
1. 响应行(Status Line)
- 格式:
HTTP版本 状态码 描述
- 示例:
HTTP/1.1 200 OK
2. 响应头(Response Headers)
- 如:
Content-Type: text/html; charset=UTF-8 Server: py1.0
3. 空行(Empty Line)
4. 响应体(Response Body)
- 实际返回的内容,如 HTML 页面、图片等。
五、HTTP 请求类型
方法 | 特点 |
---|---|
GET | 只从服务器获取数据,不向服务器发送数据 |
POST | 向服务器发送数据,常用于表单提交 |
深入理解请求方法
- GET:适合于请求公开信息,不适合传输敏感数据。
- POST:更适合于提交表单或上传文件等需要保密的操作。
六、状态码分类
类别 | 描述 | 示例 |
---|---|---|
1xx | 信息性状态码 | 100 Continue |
2xx | 成功 | 200 OK |
3xx | 重定向 | 301 Moved Permanently |
4xx | 客户端错误 | 404 Not Found |
5xx | 服务器错误 | 500 Internal Server Error |
七、Web 服务器基本流程
- 浏览器和服务器建立 TCP 连接;
- 浏览器发送请求报文;
- 服务器接收并解析请求;
- 服务器生成响应报文;
- 服务器发送响应给浏览器;
- 浏览器渲染响应内容(HTML、CSS、JS、图片等)。
八、Python 实现简易 Web 服务器
1. 基础实现(显示 "aaa")
import socket
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(("", 8080))
tcp_server_socket.listen(128)
while True:
client_socket, addr = tcp_server_socket.accept()
recv_data = client_socket.recv(100000)
if len(recv_data) == 0:
print("客户端关闭!!!")
break
print(recv_data.decode())
response_line = "HTTP/1.1 200 OK\r\n"
response_header = "server:py1.0\r\n"
response_body = "aaa"
response_data = response_line + response_header + "\r\n" + response_body
client_socket.send(response_data.encode())
client_socket.close()
2. 支持访问静态页面
import socket
import mimetypes
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(("", 8080))
tcp_server_socket.listen(128)
while True:
client_socket, addr = tcp_server_socket.accept()
recv_data = client_socket.recv(1000000)
if len(recv_data) == 0:
print("客户端关闭!!!")
break
recv_data = recv_data.decode()
print("请求报文!!!:", recv_data)
path_list = recv_data.split(" ")
request_path = path_list[1]
if request_path == "/":
request_path = "/index.html"
try:
f = open("./static" + request_path, "rb")
file_data = f.read()
f.close()
mime_type, _ = mimetypes.guess_type(request_path)
response_line = "HTTP/1.1 200 OK\r\n"
response_header = f"Content-Type: {mime_type}\r\nServer: py1.0\r\n"
response_data = (response_line + response_header + "\r\n").encode() + file_data
client_socket.send(response_data)
except Exception as e:
print("异常信息:", e)
response_line = "HTTP/1.1 404 NOT FOUND\r\n"
response_header = "Content-Type: text/html; charset=UTF-8\r\n"
response_body = "对不起 你访问的页面不存在!!!"
response_data = response_line + response_header + "\r\n" + response_body
client_socket.send(response_data.encode())
client_socket.close()
异常处理的重要性
在尝试打开不存在的文件时,通过捕获异常(如FileNotFoundError
),我们可以优雅地返回一个404响应给客户端,告知其请求的资源未找到。
MIME类型支持
为了正确展示不同类型的文件(比如HTML、CSS、JavaScript、图片等),我们需要设置正确的Content-Type
头部信息。这可以通过检查文件扩展名来确定,并根据不同的MIME类型返回相应的头部信息。
九、常见优化建议
- 多线程/异步处理:对于高并发场景,考虑使用多线程或异步编程模型来提高服务器性能。
- 安全性考量:确保所有输入都经过验证和清理,防止SQL注入等攻击。
- 日志记录:实现详细的访问日志记录功能,便于后期维护和故障排查。