django -- web框架的本质
web框架本质
我们可以这样理解:所有的Web应用本质上就是一个socket服务端,而用户的浏览器就是一个socket客户端。 这样我们就可以自己实现Web框架了。
下面代码是一个简单的socket服务
import socket sk = socket.socket() sk.bind(("127.0.0.1", 8080)) sk.listen() while True: conn, addr = sk.accept() data = conn.recv(1024) conn.send(b"OK") conn.close()
启动服务之后,用浏览器去访问127.0.0.1:8080
发现提示的响应无效,这时我们就要去了解一下HTTP协议
用户的浏览器一输入网址,会给服务端发送数据,那浏览器会发送什么数据?怎么发?这个谁来定? 你这个网站是这个规定,他那个网站按照他那个规定,这互联网还能玩么?
所以,必须有一个统一的规则,让大家发送消息、接收消息的时候有个格式依据,不能随便写。
这个规则就是HTTP协议,以后浏览器发送请求信息也好,服务器回复响应信息也罢,都要按照这个规则来。
HTTP协议主要规定了客户端和服务器之间的通信格式,那HTTP协议是怎么规定消息格式的呢?
让我们首先打印下我们在服务端接收到的消息是什么。
import socket sk = socket.socket() sk.bind(("127.0.0.1", 8080)) sk.listen() while True: conn, addr = sk.accept() data = conn.recv(1024) print(data) # 打印出浏览器发来的消息 conn.send(b"OK") conn.close()
输出
b'GET / HTTP/1.1\r\nHost: 127.0.0.1:8080\r\nConnection: keep-alive\r\nCache-Control: max-age=0\r\nUpgrade-Insecure-Requests: 1\r\nUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Safari/537.36\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3\r\nAccept-Encoding: gzip, deflate, br\r\nAccept-Language: zh-CN,zh;q=0.9\r\n\r\n'
然后我们再看一下我们访问博客园官网时浏览器收到的响应信息是什么。
响应相关信息可以在浏览器调试窗口的network标签页中看到。
HTTP协议对收发消息的格式要求
每个HTTP请求和响应都遵循相同的格式,一个HTTP包含Header和Body两部分,其中Body是可选的。 HTTP响应的Header中有一个 Content-Type
表明响应的内容格式。如 text/html
表示HTML网页。
HTTP GET请求的格式
HTTP响应的格式
经过上面的补充学习,我们知道了要想让我们自己写的web server端正经起来,必须要让我们的Web server在给客户端回复消息的时候按照HTTP协议的规则加上响应状态行,这样我们就实现了一个正经的Web框架了。
import socket sk = socket.socket() sk.bind(("127.0.0.1", 8080)) sk.listen() while 1: conn, addr = sk.accept() data = conn.recv(1024) print(data) conn.send(b'HTTP/1.1 200 OK\r\n\r\n ok') conn.close()
然后访问127.0.0.1:8080返回了我们定义的数据
根据不同的路径返回不同的内容
这样就结束了吗? 如何让我们的Web服务根据用户请求的URL不同而返回不同的内容呢?
小事一桩,我们可以从请求相关数据里面拿到请求URL的路径,然后拿路径做一个判断...
""" 根据URL中不同的路径返回不同的内容 """ import socket sk = socket.socket() sk.bind(("127.0.0.1", 8080)) # 绑定IP和端口 sk.listen() # 监听 while 1: # 等待连接 conn, add = sk.accept() data = conn.recv(8096) # 接收客户端发来的消息 # 从data中取到路径 data = str(data, encoding="utf8") # 把收到的字节类型的数据转换成字符串 # 按\r\n分割 data1 = data.split("\r\n")[0] url = data1.split()[1] # url是我们从浏览器发过来的消息中分离出的访问路径 conn.send(b'HTTP/1.1 200 OK\r\n\r\n') # 因为要遵循HTTP协议,所以回复的消息也要加状态行 # 根据不同的路径返回不同内容 if url == "/index/": response = b"index" elif url == "/home/": response = b"home" else: response = b"404 not found!" conn.send(response) conn.close()