什么是框架?

在生活中就像我们想到的一样,框架指的我们在做一件事情的时候搭的骨架来完成基础的功能。

例如盖楼,开发商建的毛坯房就是楼的骨架,毛坯房的基础功能就是能住。如果想住的舒服

用户根据自己的需求来摆放物品。例如客厅放沙发,电视。主卧放床和衣柜等等。

例如明星开演唱会,舞台的搭建就是一个骨架,舞台基础的功能就是明星能有地方唱歌跳舞,如果想要气氛,可以在舞台上摆放不同的物品。

程序中的框架和生活中搭建的框架的功能是相同的,框架来完成一些基础的工作,

程序员在此基础上开发实现自己业务功能的代码;

把程序员从繁琐的重复性的代码中解脱出来,提交开发效率;

python 构建数据处理框架 python基础框架的构架_python 构建数据处理框架

 

WEB框架的本质

我们可以这样理解:所有的Web应用框架本质上就是一个socket服务端,而用户的浏览器就是一个socket客户端。 一些常用框架(Django、Tornado、Flash)是对socket服务端进行的封装,使得基础功能更加完善。

 

自定义初始web框架

 

import socket

server_sk=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server_sk.bind(('127.0.0.1',9999))
server_sk.listen(128)

while True:
    print('等待客户连接')
    client_sk,addr=server_sk.accept()
    content=client_sk.recv(1024)       #默认是二进制内容
    print(content)                     #接收到是内容是请求报文
    content=content.decode('utf-8')
    print(content)

    #给浏览器发送内容
    client_sk.send('HTTP/1.1 200 OK\r\n'.encode('utf-8'))  #设置响应首行
    # client_sk.send('Content-Type: text/html;charset=gbk')
    client_sk.send('\r\n'.encode('utf-8'))                   #设置响应空格
    client_sk.send('很好'.encode('utf-8'))                     #设置响应体内容,可以发送英文,但是发送中文会变化乱码


    client_sk.close()

我们通过十几行代码简单地演示了web 框架的本质。

接下来就让我们继续完善我们的自定义web框架吧!

扩展:

解决返回给浏览器中文乱码问题:

import socket
server_sk=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server_sk.bind(('127.0.0.1',9999))
server_sk.listen(23)        #可以连接客户端的个数
while True:
    client_sk,addr=server_sk.accept()
    content=client_sk.recv(1024).decode('utf-8')
    print(content)

    #向浏览器发送内容
    msg1='HTTP/1.1 200 OK\r\n'.encode('utf-8')  #设置响应首行   
    # 设置响应头,告诉浏览器返回的是文本类型的html,并且以utf-8格式解码
    msg2='Content-Type:text/html;charset=utf-8\r\n'.encode('utf-8')   #通过设置响应头来告诉浏览器以什么方式解码来避免中文出现乱码
    msg3='\r\n'.encode('utf-8')
    msg4='你好浏览器'.encode('utf-8')
    client_sk.send(msg1)
    client_sk.send(msg2)
    client_sk.send(msg3)
    client_sk.send(msg4)

    client_sk.close()

(2).根据不同的路径返回不同的内容

如何让我们的Web服务根据用户请求的URL不同而返回不同的内容呢?

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

 

import socket
server_sk=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server_sk.bind(('127.0.0.1',9999))
server_sk.listen(34)

while True:
    client_sk,addrs=server_sk.accept()
    content=client_sk.recv(1024).decode('utf-8')
    print("客户端发来贺电:")
    print(content)

    #切出index
    con=content.split(' ')
    print(con)
    con1=con[1].split('/')
    path=con1[1]

    #根据url中的内容返回不同页面
    if path=='index':
        msg='这是{}页面'.format(path).encode('utf-8')
    elif path=='home':
        msg='这是{}页面'.format(path).encode('utf-8')
    else:
        msg='sorry {} not find'.format(path).encode('utf-8')

    #向页面返回内容
    msg1='HTTP/1.1 200 ok\r\n'.encode('utf-8')
    msg2='Content-Type:text/html;charset=utf-8\r\n'.encode('utf-8')

    msg3='\r\n'.encode('utf-8')
    client_sk.send(msg1)
    client_sk.send(msg2)
    client_sk.send(msg3)
    client_sk.send(msg)


    #关闭客户端
    client_sk.close()

(3).根据不同的路径返回不同的内容--函数版

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

但是问题又来了,如果有很多很多路径要判断怎么办?难道要挨个写if判断? 当然不用,我们有更聪明的办法。

import socket
server_sk=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server_sk.bind(('127.0.0.1',9999))
server_sk.listen(34)

while True:
    client_sk,addrs=server_sk.accept()
    content=client_sk.recv(1024).decode('utf-8')
    print("客户端发来贺电:")
    print(content)

    #切出index
    con=content.split(' ')
    print(con)
    con1=con[1].split('/')
    path=con1[1]

    # 向页面返回内容
    msg1 = 'HTTP/1.1 200 ok\r\n'.encode('utf-8')
    msg2 = 'Content-Type:text/html;charset=utf-8\r\n'.encode('utf-8')
    msg3 = '\r\n'.encode('utf-8')
    client_sk.send(msg1)
    client_sk.send(msg2)
    client_sk.send(msg3)

    def index():
        msg = '这是{}页面\r\n'.format(path).encode('utf-8')
        client_sk.send(msg)
        # return msg

    def home():
        msg = '这是{}页面'.format(path).encode('utf-8')
        client_sk.send(msg)

    def other():
        msg = 'sorry {} not find'.format(path).encode('utf-8')
        client_sk.send(msg)



    #根据url中的内容返回不同页面
    if path=='index':
        index()
    elif path=='home':
        home()
    else:
        other()

    #关闭客户端
    client_sk.close()

看起来上面的代码还是要挨个写if判断,怎么办?我们还是有办法!

import socket
server_sk=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server_sk.bind(('127.0.0.1',9999))
server_sk.listen(34)

def index(path):
    msg = '这是{}页面\r\n'.format(path).encode('utf-8')
    return msg

def home(path):
    msg = '这是{}页面'.format(path).encode('utf-8')
    return msg

def error(path):
    msg = 'sorry {} not find'.format(path).encode('utf-8')
    return msg

#定义一个url和执行函数对应关系的列表
path_lst = [
    ('/index', index),
    ('/home', home),
]

while True:
    client_sk,addrs=server_sk.accept()
    content=client_sk.recv(1024).decode('utf-8')
    print("客户端发来贺电:")
    print(content)


    #切出index
    con=content.split(' ')
    path=con[1]



    # 向页面返回内容
    msg1 = 'HTTP/1.1 200 ok\r\n'.encode('utf-8')
    msg2 = 'Content-Type:text/html;charset=utf-8\r\n'.encode('utf-8')
    msg3 = '\r\n'.encode('utf-8')

    client_sk.send(msg1)
    client_sk.send(msg2)
    client_sk.send(msg3)

    # 2.定义一个变量来接受对应的函数名称
    func = None
    # 3.变量列表,查收是否有对应的url
    for path_tup in path_lst:
        if path_tup[0] == path:
            func = path_tup[1]

    if func:
        msg = func(path)
    else:
        msg = error(path)
    client_sk.send(msg)
    #关闭客户端
    client_sk.close()


完美解决了不同URL返回不同内容的问题。 但是我不想仅仅返回几个字符串,我想给浏览器返回完整的HTML内容,这又该怎么办呢?

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

import socket
server_sk=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server_sk.bind(('127.0.0.1',9999))
server_sk.listen(34)

def index(path):
    #通过这里把对应界面返回
    with open('index.html','rb') as f:
        msg=f.read()
    return msg

def home(path):
    with open('home.html', 'rb') as f:
        msg = f.read()

    return msg

def error(path):
    with open('error.html', 'rb') as f:
        msg = f.read()
    return msg

path_lst = [
    ('/index', index),
    ('/home', home),
]

while True:
    client_sk,addrs=server_sk.accept()
    content=client_sk.recv(1024).decode('utf-8')
    print("客户端发来贺电:")
    print(content)


    #切出index
    con=content.split(' ')
    path=con[1]



    # 向页面返回内容
    msg1 = 'HTTP/1.1 200 ok\r\n'.encode('utf-8')
    msg2 = 'Content-Type:text/html;charset=utf-8\r\n'.encode('utf-8')
    msg3 = '\r\n'.encode('utf-8')

    client_sk.send(msg1)
    client_sk.send(msg2)
    client_sk.send(msg3)

    func = None
    for path_tup in path_lst:
        if path_tup[0] == path:
            func = path_tup[1]

    if func:
        msg = func(path)
    else:
        msg = error(path)
    client_sk.send(msg)
    #关闭客户端
    client_sk.close()

这网页能够显示出来了,但是都是静态的啊。页面的内容都不会变化的,我想要的是动态网站。

没问题,我也有办法解决。我选择使用字符串替换来实现这个需求。(这里使用时间戳来模拟动态的数据)

import socket
server_sk=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server_sk.bind(('127.0.0.1',9999))
server_sk.listen(34)

def index(path):
    #通过这里把对应界面返回
    with open('index.html','r',encoding='utf-8') as f:
        msg=f.read()
        msg=msg.replace('xxoo',path).encode('utf-8')
    return msg

def home(path):
    with open('home.html', 'r',encoding='utf-8') as f:
        msg = f.read()
        msg=msg.replace('xxoo', path).encode('utf-8')
    return msg

def error(path):
    with open('error.html', 'r',encoding='utf-8') as f:
        msg = f.read()
        msg=msg.replace('xxoo', path).encode('utf-8')
    return msg

path_lst = [
    ('/index', index),
    ('/home', home),
]

while True:
    client_sk,addrs=server_sk.accept()
    content=client_sk.recv(1024).decode('utf-8')
    print("客户端发来贺电:")
    print(content)


    #切出index
    con=content.split(' ')
    path=con[1]



    # 向页面返回内容
    msg1 = 'HTTP/1.1 200 ok\r\n'.encode('utf-8')
    msg2 = 'Content-Type:text/html;charset=utf-8\r\n'.encode('utf-8')
    msg3 = '\r\n'.encode('utf-8')

    client_sk.send(msg1)
    client_sk.send(msg2)
    client_sk.send(msg3)

    func = None
    for path_tup in path_lst:
        if path_tup[0] == path:
            func = path_tup[1]

    if func:
        msg = func(path)
    else:
        msg = error(path)
    client_sk.send(msg)
    #关闭客户端
    client_sk.close()

目录结构

python 构建数据处理框架 python基础框架的构架_HTTP_02

总结

1.web框架的本质:socket 服务端 与浏览器的通讯。
2.socket 服务端功能可以划分为3部分:
 - a.负责与浏览器收发消息(socket)在python中有专门的框架

         wsgiref/uWsgi/gunicorn...
 - b.根据用户访问不同的路径执行不同的函数
 - c.从HTML中读取出内容,并且完成字符串的替换
3.Python中 web 框架的分类:
 - 按照2上面的功能分类
  (1).框架自带a,b,c 功能          ----> Tornado
  (2).框架自带b,c,使用第三方的a   ---->Django
  (3).框架自带b,使用第三方的a,c  ---->Flask
 -按照另一个维度划分
  (1).Diango ,Tornado-->大而全(做一个网站用到的技术都有)
  (2).其他 例如 Flask 轻量级只封装了核心功能。

a部分和b、c 部分通讯需要遵守WSGI 协议。