了解http协议
http请求头
GET / HTTP/1.1
Host: www.baidu.com
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
Sec-Fetch-Site: none
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
最主要的头两行分析如下:
- GET表示一个读取请求,将从服务器获得网页数据,/表示URL的路径,URL总是以/开头,/就表示首页,最后的HTTP/1.1指示采用的HTTP协议版本是1.1。
- 目前HTTP协议的版本就是1.1,但是大部分服务器也支持1.0版本,主要区别在于1.1版本允许多个HTTP请求复用一个TCP连接,以加快传输速度。
- Host: www.baidu.com表示请求的域名是www.baidu.com。如果一台服务器有多个网站,服务器就需要通过Host来区分浏览器请求的是哪个网站。
http响应头
HTTP/1.1 200 OK
Bdpagetype: 2
Bdqid: 0x8ef7ae5901149cf7
Cache-Control: private
Connection: Keep-Alive
Content-Encoding: gzip
Content-Type: text/html;charset=utf-8
Date: Wed, 28 Aug 2019 01:59:49 GMT
Expires: Wed, 28 Aug 2019 01:59:48 GMT
Server: BWS/1.1
Set-Cookie: BDSVRTM=249; path=/
Set-Cookie: BD_HOME=1; path=/
Set-Cookie: H_PS_PSSID=1426_21111_20697_29522_29518_29099_29568_29220_26350; path=/; domain=.baidu.com
Strict-Transport-Security: max-age=172800
X-Ua-Compatible: IE=Edge,chrome=1
Transfer-Encoding: chunked
说明:
- 200表示一个成功的响应,后面的OK是说明。
- Content-Type指示响应的内容,这里是text/html表示HTML网页。
- 请求头和响应头通过\r\n来换行。
- 响应头和body响应体中也通过\r\n来分隔。
简单的http服务器
有多简单呢?运行程序后打开浏览器,只能显示hello world。
import socket
def service_client(new_socket):
# 接受浏览器发过来的http请求
# GET / HTTP/1.1
request = new_socket.recv(1024)
print(request)
# 返回http响应
resposne = "HTTP/1.1 200 OK\r\n"
resposne += "\r\n"
resposne += "<h1>hello world</h1>"
new_socket.send(resposne.encode("utf-8"))
# 关闭套接字
new_socket.close()
def main():
# 创建套接字
http_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 防止端口被占用无法启动程序
http_server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
# 绑定端口
http_server.bind(("", 80))
# 变为监听套接字
http_server.listen(128)
while True:
# 等在新客户端连接
client, info = http_server.accept()
# 为这个客户端服务
service_client(client)
if __name__ == "__main__":
main()
单进程http服务器
它上之前有一个升级就是可以返回静态的html页面。
import socket
import re
def service_client(new_socket):
# 接受浏览器发过来的http请求
# GET / HTTP/1.1
request = new_socket.recv(1024).decode("utf-8")
# print(request)
request_lines = request.splitlines()
req = re.match(r"[^/]+(/\S*)", request_lines[0])
file_name: str = ""
if req:
file_name = req.group(1)
if file_name == "/":
file_name = "/index.html"
print(file_name)
# print(request_lines)
# 返回http响应
try:
# 打开要请求的html文件,并返回给客户端。网页在当前路径的html文件夹里面。
with open("./html" + file_name, "r", encoding="utf-8") as f:
resposne = "HTTP/1.1 200 OK\r\n"
resposne += "\r\n"
# resposne += "<h1>hello world</h1>"
resposne += f.read()
except Exception as e:
resposne = "HTTP/1.1 400 NOT FOUND\r\n"
resposne += "\r\n"
resposne += "--file not found--"
new_socket.send(resposne