Django之web框架的本质

前言

由上一篇HTTP协议,我们简单的知道HTTP那点事儿。但是我们的目的是在此基础上编写web程序。所以,接下来通过一个个示例了解,web框架的本质——通俗的说,web框架封装了socket、数据库操作、路由分发、模板配置等,留给我们现成的接口,让我们更专注业务逻辑本身。

一个简单的web示例

import socket

# 1. 创建socket对象
sk = socket.socket()

# 2. 绑定IP和端口
sk.bind(('127.0.0.1', 8888))

# 3. 监听
sk.listen(5)

# 4. 循环监听

while 1:
    conn, addr = sk.accept()  # 等待连接
    received_data = conn.recv(8192)  # 接收数据
    print(received_data)  # b'GET / HTTP/1.1\r\nHost: 127.0.0.1:8888\r\nConnection: keep-alive\r\nUpgrade-Insecure-Requests: 1\r\nUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 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,en;q=0.8\r\nCookie: csrftoken=FQW7H4SEVPRqdqIr4vSeiP3EdjX2C0JY7VwCdmXevoXcPjiAMBtNptkiZLHqXo4d\r\n\r\n'

    conn.send(b'HTTP/1.1 200 OK\r\n\r\n')  # 接收数据
    conn.send(b'<h1>Successful</h1>')
    conn.close()  # 关闭连接

现在,使用浏览器地址栏访问http://127.0.0.1:8888/,就会得到Successful

根据不同路径返回不同内容

第一版·普通版

import socket

# 创建socket对象
sk = socket.socket()

# 绑定IP和端口
sk.bind(('127.0.0.1', 8888))

# 监听
sk.listen()

while True:
    # 等待连接
    conn, addr = sk.accept()
    # 接收数据
    data = conn.recv(8192)
    data = data.decode('utf-8')
    url = data.split()[1]
    print(url)
    # 返回状态行
    conn.send(b'HTTP/1.1 200 OK\r\n\r\n')
    if url == '/oumei':
        conn.send(b'<h1>oumei</h1>')
    elif url == '/rihan':
        conn.send(b'<h1>rihan</h1>')
    else:
        conn.send(b'<h1>404</h1>')
    # 关闭连接
    conn.close()

第二版·函数版

import socket
# 创建socket对象
sk = socket.socket()
# 绑定IP和端口
sk.bind(('127.0.0.1', 8888))
# 监听
sk.listen()
def oumei(url):
    ret = 'oumei   -  {}'.format(url)
    return ret.encode('utf-8')
def rihan(url):
    ret = 'rihan////   -  {}'.format(url)
    return ret.encode('utf-8')
while True:
    # 等待连接
    conn, addr = sk.accept()
    # 接收数据
    data = conn.recv(8192)
    data = data.decode('utf-8')
    url = data.split()[1]
    print(url)
    # 返回状态行
    conn.send(b'HTTP/1.1 200 OK\r\n\r\n')
    if url == '/oumei':
        ret = oumei(url)
    elif url == '/rihan':
        ret = rihan(url)
    else:
        ret = b'404 not found'
    conn.send(ret)
    # 关闭连接
    conn.close()

第三版·函数进阶版

import socket
# 创建socket对象
sk = socket.socket()
# 绑定IP和端口
sk.bind(('127.0.0.1', 8888))
# 监听
sk.listen()
def oumei(url):
    ret = 'oumei   -  {}'.format(url)
    return ret.encode('utf-8')
def rihan(url):
    ret = 'rihan////   -  {}'.format(url)
    return ret.encode('utf-8')
def guochan(url):
    ret = 'guochan   -  {}'.format(url)
    return ret.encode('utf-8')
list = [
    ('/oumei', oumei),
    ('/rihan', rihan),
    ('/guochan', guochan),
]
while True:
    # 等待连接
    conn, addr = sk.accept()
    # 接收数据
    data = conn.recv(8192)
    data = data.decode('utf-8')
    url = data.split()[1]
    print(url)
    # 返回状态行
    conn.send(b'HTTP/1.1 200 OK\r\n\r\n')
    func = None
    for i in list:
        if i[0] == url:
            func = i[1]
            break
    if func:
        ret = func(url)
    else:
        ret = b'404 not found'
    conn.send(ret)
    # 关闭连接
    conn.close()

第四版·反射版

ps:仅针对当前脚本使用的反射。

import socket
sk = socket.socket()
sk.bind(("127.0.0.1", 8888))
sk.listen()
class Server(object):
    """ 模拟多个页面 """
    def europe(self):
        return "<h1>europe</h1>".encode('utf8')
    def kkc(self):
        return "<h1>kkc</h1>".encode('utf8')
    def notfond(self):
        return "<h1>404 not fond</h1>".encode('utf8')
while 1:
    # 等待请求
    conn, address = sk.accept()
    # 获取数据
    data = conn.recv(8192).decode('utf8')
    # 处理请求拿到请求路径
    # print(data)
    url = data.split(' ', 2)[1][1:]
    # print(url, data)
    # 返回数据
    server_obj = Server()
    if hasattr(server_obj, url):
        res = getattr(server_obj, url)()
    else:
        res = server_obj.notfond()
    conn.send(b'HTTP/1.1 200 OK\r\n\r\n')
    conn.send(res)
    conn.close()

返回HTML页面

首先在同级目录有个index.html页面:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="x-ua-compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Title</title>
</head>
<body>

<h1>index page</h1>

</body>
</html>

然后写server端:

import socket

# 创建socket对象
sk = socket.socket()

# 绑定IP和端口
sk.bind(('127.0.0.1', 8888))

# 监听
sk.listen()


def oumei(url):
    ret = 'oumei   -  {}'.format(url)
    return ret.encode('utf-8')


def rihan(url):
    ret = 'rihan////   -  {}'.format(url)
    return ret.encode('utf-8')


def guochan(url):
    ret = 'guochan   -  {}'.format(url)
    return ret.encode('utf-8')


def index(url):
    with open('index.html', 'rb') as f:
        ret = f.read()
        return ret


list = [
    ('/oumei', oumei),
    ('/rihan', rihan),
    ('/guochan', guochan),
    ('/index', index),
]

while True:
    # 等待连接
    conn, addr = sk.accept()
    # 接收数据
    data = conn.recv(8192)
    data = data.decode('utf-8')
    url = data.split()[1]
    print(url)

    # 返回状态行
    conn.send(b'HTTP/1.1 200 OK\r\n\r\n')
    func = None
    for i in list:
        if i[0] == url:
            func = i[1]
            break

    if func:
        ret = func(url)
    else:
        ret = b'404 not found'

    conn.send(ret)

    # 关闭连接
    conn.close()

返回动态页面

在同级目录有个tiem.html页面:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>当前时间是: @@time@@ </h1>
</body>
</html>

在来实现代码:

import socket
import time

# 创建socket对象
sk = socket.socket()

# 绑定IP和端口
sk.bind(('0.0.0.0', 8000))

# 监听
sk.listen()


def oumei(url):
    ret = 'oumei   -  {}'.format(url)
    return ret.encode('utf-8')


def rihan(url):
    ret = 'rihan////   -  {}'.format(url)
    return ret.encode('utf-8')


def guochan(url):
    ret = 'guochan   -  {}'.format(url)
    return ret.encode('utf-8')


def index(url):
    with open('index.html', 'rb') as f:
        ret = f.read()
        return ret


def timer(url):
    now = time.strftime('%Y-%m-%d %H:%M:%S')
    with open('time.html', 'r', encoding='utf-8') as f:
        data = f.read()
        data = data.replace('@@time@@', now)

        return data.encode('utf-8')


list = [
    ('/oumei', oumei),
    ('/rihan', rihan),
    ('/guochan', guochan),
    ('/index', index),
    ('/time', timer),
]

while True:
    # 等待连接
    conn, addr = sk.accept()
    # 接收数据
    data = conn.recv(8096)
    data = data.decode('utf-8')
    url = data.split()[1]
    print(url)

    # 返回状态行
    conn.send(b'HTTP/1.1 200 OK\r\n\r\n')
    func = None
    for i in list:
        if i[0] == url:
            func = i[1]
            break

    if func:
        ret = func(url)
    else:
        ret = b'404 not found'

    conn.send(ret)

    # 关闭连接
    conn.close()

总结

正如文章开始所示,web框架本质就是一个socket服务端。

web框架功能:

  • socket收发消息
  • 根据不同的路径返回不同的内容
  • 可以返回动态页面(使用字符串替换等方式进行模板渲染)

Python中主流web框架:


欢迎斧正,that's all see also:[简说Python Web异步框架](https://www.yuanrenxue.com/tricks/introduce-python-asynchronous-framework.html)
posted @ 2019-06-05 10:37  听雨危楼  阅读(347)  评论(0编辑  收藏  举报