自定义web框架

web框架的根本是socket的代码,那么我们可以基于socket服务端的十几行代码写一个我们自己的web框架。

我们先不处理浏览器发送的请求,先让浏览器能显示我们web框架返回的信息,那我们就要按照HTTP协议的格式来发送响应。

 1 import socket    
 2     
 3 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)    
 4 sock.bind(('127.0.0.1', 8000))    
 5 sock.listen()    
 6     
 7 while True:    
 8     conn, addr = sock.accept()    
 9     data = conn.recv(8096)    
10     # 给回复的消息加上响应状态行    
11     conn.send(b"HTTP/1.1 200 OK\r\n\r\n")    
12     conn.send(b"OK")    
13     conn.close()    
web框架核心代码

下面就是继续完善自定义的web框架。

1. 根据不同的路径返回不同的内容

现在的一个问题就是如何让我们的web服务根据用户请求的URL不同,然后返回不同的内容?

这个问题,我们可以从请求相关数据里面拿到请求URL的路径,然后拿路径做一个判断。

 1 import socket  
 2   
 3 sk = socket.socket()  
 4 sk.bind(("127.0.0.1", 8080))  # 绑定IP和端口  
 5 sk.listen()  # 监听  
 6   
 7 while True:  
 8     # 等待连接  
 9     conn, add = sk.accept()  
10     data = conn.recv(8096)  # 接收客户端发来的消息  
11     # 从data中取到路径  
12     data = str(data, encoding="utf8")  # 把收到的字节类型的数据转换成字符串  
13     # 按\r\n分割  
14     data1 = data.split("\r\n")[0]  
15     url = data1.split()[1]  # url是我们从浏览器发过来的消息中分离出的访问路径  
16     conn.send(b'HTTP/1.1 200 OK\r\n\r\n')  # 因为要遵循HTTP协议,所以回复的消息也要加状态行  
17     # 根据不同的路径返回不同内容  
18     if url == "/index/":  
19         response = b"index"  
20     elif url == "/home/":  
21         response = b"home"  
22     else:  
23         response = b"404 not found!"  
24   
25     conn.send(response)  
26     conn.close()  
根据URL中不同的路径返回不同的内容

2. 根据不同的路径返回不同的内容——函数版

上面的代码解决了不同的URL路径,返回不同内容的需求。

返回的内容只是简单的几个字符,那么可以将返回的内容封装成一个函数。

 1   
 2 import socket  
 3   
 4 sk = socket.socket()  
 5 sk.bind(("127.0.0.1", 8080))  # 绑定IP和端口  
 6 sk.listen()  # 监听  
 7   
 8   
 9 # 将返回不同的内容部分封装成函数  
10 def func(url):  
11     s = "这是{}页面!".format(url)  
12     return bytes(s, encoding="utf8")  
13   
14   
15 while True:  
16     # 等待连接  
17     conn, add = sk.accept()  
18     data = conn.recv(8096)  # 接收客户端发来的消息  
19     # 从data中取到路径  
20     data = str(data, encoding="utf8")  # 把收到的字节类型的数据转换成字符串  
21     # 按\r\n分割  
22     data1 = data.split("\r\n")[0]  
23     url = data1.split()[1]  # url是我们从浏览器发过来的消息中分离出的访问路径  
24     conn.send(b'HTTP/1.1 200 OK\r\n\r\n')  # 因为要遵循HTTP协议,所以回复的消息也要加状态行  
25     # 根据不同的路径返回不同内容,response是具体的响应体  
26     if url == "/index/":  
27         response = func(url)  
28     elif url == "/home/":  
29         response = func(url)  
30     else:  
31         response = b"404 not found!"  
32   
33     conn.send(response)  
34     conn.close()  
根据URL中不同的路径返回不同的内容--函数版

3. 根据不同的路径返回不同内容——函数进阶版

上面的代码只是简单的写了一个函数,那么继续延伸下去,就可以写多个函数,不同的路径对应执行不同的函数拿到结果。

 1 import socket  
 2   
 3 sk = socket.socket()  
 4 sk.bind(("127.0.0.1", 8080))  # 绑定IP和端口  
 5 sk.listen()  # 监听  
 6   
 7   
 8 # 将返回不同的内容部分封装成不同的函数  
 9 def index(url):  
10     s = "这是{}页面XX!".format(url)  
11     return bytes(s, encoding="utf8")  
12   
13   
14 def home(url):  
15     s = "这是{}页面。。!".format(url)  
16     return bytes(s, encoding="utf8")  
17   
18   
19 # 定义一个url和实际要执行的函数的对应关系  
20 list1 = [  
21     ("/index/", index),  
22     ("/home/", home),  
23 ]  
24   
25 while True:  
26     # 等待连接  
27     conn, add = sk.accept()  
28     data = conn.recv(8096)  # 接收客户端发来的消息  
29     # 从data中取到路径  
30     data = str(data, encoding="utf8")  # 把收到的字节类型的数据转换成字符串  
31     # 按\r\n分割  
32     data1 = data.split("\r\n")[0]  
33     url = data1.split()[1]  # url是我们从浏览器发过来的消息中分离出的访问路径  
34     conn.send(b'HTTP/1.1 200 OK\r\n\r\n')  # 因为要遵循HTTP协议,所以回复的消息也要加状态行  
35     # 根据不同的路径返回不同内容  
36     func = None  # 定义一个保存将要执行的函数名的变量  
37     for item in list1:  
38         if item[0] == url:  
39             func = item[1]  
40             break  
41     if func:  
42         response = func(url)  
43     else:  
44         response = b"404 not found!"  
45   
46     # 返回具体的响应消息  
47     conn.send(response)  
48     conn.close()  
根据URL中不同的路径返回不同的内容--函数进阶版

4. 根据不同的路径返回不同的内容——函数进阶版(返回具体的HTML文件)

如果想给浏览器返回完整的HTML内容,那么又应该怎么做呢?

不管是什么内容,最后都是转换成字节数据发送出去。我们可以打开HTML文件,读取出它内部的二进制文件,然后再发送给浏览器。

 1 import socket  
 2   
 3 sk = socket.socket()  
 4 sk.bind(("127.0.0.1", 8080))  # 绑定IP和端口  
 5 sk.listen()  # 监听  
 6   
 7   
 8 # 将返回不同的内容部分封装成不同的函数  
 9 def index(url):  
10     # 读取index.html页面的内容  
11     with open("index.html", "r", encoding="utf8") as f:  
12         s = f.read()  
13     # 返回字节数据  
14     return bytes(s, encoding="utf8")  
15   
16   
17 def home(url):  
18     with open("home.html", "r", encoding="utf8") as f:  
19         s = f.read()  
20     return bytes(s, encoding="utf8")  
21   
22   
23 # 定义一个url和实际要执行的函数的对应关系  
24 list1 = [  
25     ("/index/", index),  
26     ("/home/", home),  
27 ]  
28   
29 while True:  
30     # 等待连接  
31     conn, add = sk.accept()  
32     data = conn.recv(8096)  # 接收客户端发来的消息  
33     # 从data中取到路径  
34     data = str(data, encoding="utf8")  # 把收到的字节类型的数据转换成字符串  
35     # 按\r\n分割  
36     data1 = data.split("\r\n")[0]  
37     url = data1.split()[1]  # url是我们从浏览器发过来的消息中分离出的访问路径  
38     conn.send(b'HTTP/1.1 200 OK\r\n\r\n')  # 因为要遵循HTTP协议,所以回复的消息也要加状态行  
39     # 根据不同的路径返回不同内容  
40     func = None  # 定义一个保存将要执行的函数名的变量  
41     for item in list1:  
42         if item[0] == url:  
43             func = item[1]  
44             break  
45     if func:  
46         response = func(url)  
47     else:  
48         response = b"404 not found!"  
49   
50     # 返回具体的响应消息  
51     conn.send(response)  
52     conn.close() 
服务器

index.html中的代码

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <meta http-equiv="x-ua-compatible" content="IE=edge">
 6     <meta name="viewport" content="width=device-width, initial-scale=1">
 7     <title>index</title>
 8 </head>
 9 <body>
10 <div>这是index页面</div>
11 </body>
12 </html>
index.html

home.html中的代码

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <meta http-equiv="x-ua-compatible" content="IE=edge">
 6     <meta name="viewport" content="width=device-width, initial-scale=1">
 7     <title>index</title>
 8 </head>
 9 <body>
10 <div>这是home页面</div>
11 </body>
12 </html>
home.html

5. 根据URL中不同的路径返回不同的内容——函数进阶版(返回独立的HTML页面)

 1 import time   
 2 import socket  
 3   
 4 sk = socket.socket()  
 5 sk.bind(("127.0.0.1", 8080))  # 绑定IP和端口  
 6 sk.listen()  # 监听  
 7   
 8   
 9 # 将返回不同的内容部分封装成不同的函数  
10 def index(url):  
11     # 读取index.html页面的内容  
12     with open("index.html", "r", encoding="utf8") as f:  
13         s = f.read()  
14     # 返回字节数据  
15     return bytes(s, encoding="utf8")  
16   
17   
18 def home(url):  
19     with open("home.html", "r", encoding="utf8") as f:  
20         s = f.read()  
21     return bytes(s, encoding="utf8")  
22   
23   
24 def timer(url):  
25     with open("time.html", "r", encoding="utf8") as f:  
26         s = f.read()  
27         s = s.replace('@@time@@', time.strftime("%Y-%m-%d %H:%M:%S"))  
28     return bytes(s, encoding="utf8")  
29   
30   
31 # 定义一个url和实际要执行的函数的对应关系  
32 list1 = [  
33     ("/index/", index),  
34     ("/home/", home),  
35     ("/time/", timer),  
36 ]  
37   
38 while True:  
39     # 等待连接  
40     conn, add = sk.accept()  
41     data = conn.recv(8096)  # 接收客户端发来的消息  
42     # 从data中取到路径  
43     data = str(data, encoding="utf8")  # 把收到的字节类型的数据转换成字符串  
44     # 按\r\n分割  
45     data1 = data.split("\r\n")[0]  
46     url = data1.split()[1]  # url是我们从浏览器发过来的消息中分离出的访问路径  
47     conn.send(b'HTTP/1.1 200 OK\r\n\r\n')  # 因为要遵循HTTP协议,所以回复的消息也要加状态行  
48     # 根据不同的路径返回不同内容  
49     func = None  # 定义一个保存将要执行的函数名的变量  
50     for item in list1:  
51         if item[0] == url:  
52             func = item[1]  
53             break  
54     if func:  
55         response = func(url)  
56     else:  
57         response = b"404 not found!"  
58   
59     # 返回具体的响应消息  
60     conn.send(response)  
61     conn.close()  
服务器

index.html代码

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <meta http-equiv="x-ua-compatible" content="IE=edge">
 6     <meta name="viewport" content="width=device-width, initial-scale=1">
 7     <title>index</title>
 8 </head>
 9 <body>
10 <div>这是index页面</div>
11 </body>
12 </html>
index.html

home.html代码

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <meta http-equiv="x-ua-compatible" content="IE=edge">
 6     <meta name="viewport" content="width=device-width, initial-scale=1">
 7     <title>index</title>
 8 </head>
 9 <body>
10 <div>这是home页面</div>
11 </body>
12 </html>
home.html

time.html代码

 1 <!doctype html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <meta name="viewport"
 6           content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
 7     <meta http-equiv="X-UA-Compatible" content="ie=edge">
 8     <title>Document</title>
 9 </head>
10 <body>
11 <h1>当前时间是:@@time@@</h1>
12 </body>
13 </html>
time.html代码

 

 

 

 

 

 

 

 

 

posted @ 2018-11-15 20:49  _杨魏  阅读(235)  评论(0编辑  收藏  举报