01.通过socket写一个简单的web框架来理解django

前言

目前,有非常多的Python框架,用来帮助你更轻松的创建web应用。这些框架把相应的模块组织起来,使得构建应用的时候可以更快捷,也不用去关注一些细节(例如socket和协议),所以需要的都在框架里了。
一个WEB框架基本都会有如下功能:
  • 接受用户的请求(socket)
  • 根据不同请求路径来分发
  • 动态
 
今天我来先通过socket来实现一个简单的web框架,可以通过浏览器来访问,也可以根据请求路径的不同来分发请求。
 

01. socket实现一个服务端

# 这个socket服务端启动之后,就可以循环接受用户的请求
# 浏览器访问http://127.0.0.1:8000之后会在浏览器展示OK


import socket
sk = socket.socket()
sk.bind(('127.0.0.1', 8000))
sk.listen(5)

while True:
    conn, addr = sk.accept()
    ret = conn.recv(1024)
    print(ret)

    conn.send(b'HTTP/1.1 200 ok\r\ncontent-type: text/html\r\n\r\n')
    conn.send(b'OK')
    conn.close()
socket服务端

02. 根据不同的路径来分发请求

import socket
sk = socket.socket()
sk.bind(('127.0.0.1', 8000))
sk.listen(5)

while True:
    conn, addr = sk.accept()
    ret = conn.recv(1024)
    url = ret.decode('utf-8').split()[1]
    print(ret)

    conn.send(b'HTTP/1.1 200 ok\r\ncontent-type: text/html; charset=utf-8\r\n\r\n')
    if url == '/index':
        data = '<h1>这是首页</h1>'.encode('utf-8')
    elif url == '/home':
        data = '<h1>HOME site</h1>'.encode('utf-8')
    else:
        data = b'<h1>400 client error</h1>'
    conn.send(data)

    conn.close()
增加根据路径来转发

 03. 封装成函数

import socket
sk = socket.socket()
sk.bind(('127.0.0.1', 8000))
sk.listen(5)

def index(url):
    return f'<h1>这是首页+{url}</h1>'

def home(url):
    return f'<h1>这是home{url}</h1>'

def api(url):
    return f'<h1>这是api{url}</h1>'

while True:
    conn, addr = sk.accept()
    ret = conn.recv(1024)
    url = ret.decode('utf-8').split()[1]
    print(ret)

    conn.send(b'HTTP/1.1 200 ok\r\ncontent-type: text/html; charset=utf-8\r\n\r\n')
    if url == '/index':
        data = index(url)
        print(data)
    elif url == '/home':
        data = home(url)
    elif url == '/api':
        data = api(url)
    else:
        data = '<h1>400 client error</h1>'
    conn.send(data.encode('utf-8'))

    conn.close()
把对应路径下的功能封装成函数

04.对上面的函数进行升级(可插拔),在不改变主代码的前提下增加功能(增加路径)

 1 import socket
 2 sk = socket.socket()
 3 sk.bind(('127.0.0.1', 8000))
 4 sk.listen(5)
 5 
 6 def index(url):
 7     return f'<h1>这是首页+{url}</h1>'
 8 
 9 def home(url):
10     return f'<h1>这是home{url}</h1>'
11 
12 def api(url):
13     return f'<h1>这是api{url}</h1>'
14 
15 def test(url):
16     return f'<h1>这是api{url}</h1>'
17 
18 lst = [
19     ('/index', index),
20     ('/home', home),
21     ('api', api),
22     ('/test', test)
23 ]
24 
25 while True:
26     conn, addr = sk.accept()
27     ret = conn.recv(1024)
28     url = ret.decode('utf-8').split()[1]
29     # print(ret)
30 
31     conn.send(b'HTTP/1.1 200 ok\r\ncontent-type: text/html; charset=utf-8\r\n\r\n')
32     func = None
33     for i in lst:
34         if i[0] == url:
35             # data = i[1](url)
36             # func = getattr(i, i[0], None)
37             func = i[1]
38             print(func)
39             break
40 
41     if func:
42         data = func(url)
43     else:
44         data = '<h1>400 client error</h1>'
45 
46     conn.send(data.encode('utf-8'))
47 
48     conn.close()
函数(可插拔)

改成上面的写法之后,以后有新路径需要增加时,我们不需要改变while True下面的内容了,只需要增加一个对应的函数,

然后把路径和函数的对应关系放到lst列表中就好了,这样写扩展性比较强;

05.动态返回html内容

import time
import socket
sk = socket.socket()
sk.bind(('127.0.0.1', 8000))
sk.listen(5)

def index(url):
    return f'<h1>这是首页+{url}</h1>'

def home(url):
    with open('index.html', mode='r', encoding='utf-8') as f1:
        content = f1.read()
        print(content)
    return content

def api(url):
    return f'<h1>这是api{url}</h1>'

def test(url):
    return f'<h1>这是api{url}</h1>'


#动态显示html内容,通过字符串替换的方式
def timer(url):
    with open('\timer.html', mode='r', encoding='utf-8') as f2:
        content = f2.read()
    # now_time = time.time()
    now1 = time.strftime('%Y-%m-%d %H:%M:%S')
    content = content.replace('#time#', now1)
    return content


lst = [
    ('/index', index),
    ('/home', home),
    ('api', api),
    ('/test', timer),
    ('/time', timer),
]


while True:
    conn, addr = sk.accept()
    ret = conn.recv(1024)
    url = ret.decode('utf-8').split()[1]
    print(ret)

    conn.send(b'HTTP/1.1 200 ok\r\ncontent-type: text/html; charset=utf-8\r\n\r\n')
    func = None
    for i in lst:
        if i[0] == url:
            # data = i[1](url)
            # func = getattr(i, i[0], None)
            func = i[1]
            break

    if func:
        data = func(url)
    else:
        data = '<h1>400 client error</h1>'

    conn.send(data.encode('utf-8'))

    conn.close()
动态返回html内容

 

就这样一个简单的web框架就写完了,当然这只是做实验方便理解Django之类的框架。 Django框架上面这些都不用写,它们socket都已经被封装好了,还有很多功能都封装好了,我们只需要在Django里面写逻辑代码就行了;

w

 

posted @ 2019-12-11 16:15  Arvin-Tao  阅读(488)  评论(0)    收藏  举报