前言

由上一篇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)

版权声明:本文为Neeo原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/Neeo/articles/10978230.html