第二百五十六节,Web框架
Web框架
Web框架本质
众所周知,对于所有的Web应用,本质上其实就是一个socket服务端,用户的浏览器其实就是一个socket客户端。
举例:
#!/usr/bin/env python #coding:utf-8 import socket #导入单线程通讯模块 def handle_request(client): #发送内容函数 buf = client.recv(1024) #设置最大传输字节 client.sendall(bytes("HTTP/1.1 200 OK\r\n\r\n", encoding='utf-8')) #向客户端发送内容,以字节形式发送 client.sendall(bytes("Hello, World欢迎访问", encoding='utf-8')) #向客户端发送内容 def main(): #创建通讯函数 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #创建服务端通讯对象 sock.bind(('localhost',8082)) #在服务端设置服务端ip和端口 sock.listen(5) #监听IP和端口,设置一个参数,表示最多连接排队数量 while True: #循环 connection, address = sock.accept() #等待接收客户端的请求,一旦有客户端请求连接,就会返回两个值,一个是连接对象,一个是客户端的地址信息,所以需要两个变量来接收 handle_request(connection) #执行handle_request函数,将客户端请求连接传入handle_request函数 connection.close() #关闭连接 if __name__ == '__main__': #wds系统下if __name__ == "__main__"才能创建进程,我们调试没关系,以后在Linux系统没这个问题 main() #执行main函数
上述通过socket来实现了其本质,而对于真实开发中的python web程序来说,一般会分为两部分:服务器程序和应用程序。服务器程序负责对socket服务器进行封装,并在请求到来时,对请求的各种数据进行整理。应用程序则负责具体的逻辑处理。为了方便应用程序的开发,就出现了众多的Web框架,例如:Django、Flask、web.py 等。不同的框架有不同的开发方式,但是无论如何,开发出的应用程序都要和服务器程序配合,才能为用户提供服务。这样,服务器程序就需要为不同的框架提供不同的支持。这样混乱的局面无论对于服务器还是框架,都是不好的。对服务器来说,需要支持各种不同框架,对框架来说,只有支持它的服务器才能被开发出的应用使用。这时候,标准化就变得尤为重要。我们可以设立一个标准,只要服务器程序支持这个标准,框架也支持这个标准,那么他们就可以配合使用。一旦标准确定,双方各自实现。这样,服务器可以支持更多支持标准的框架,框架也可以使用更多支持标准的服务器。
所以,对于Web框架来说分为两类,一类是即包含了socket服务端,有包含了逻辑处理,一类是只包含逻辑处理需要另外做socket服务端
python标准库提供的独立WSGI服务器称为wsgiref。
WSGI(Web Server Gateway Interface)是一种规范,它定义了使用python编写的web app与web server之间接口格式,实现web app与web server间的解耦。
wsgiref模块,python标准库提供的独立WSGI服务器称为wsgiref,就是Web框架逻辑处理包含了socket服务端
注意:wsgiref模块在python3以上版本有问题,在2.7上可以使用,所以下面的列子在2.7上运行的
#!/usr/bin/env python #coding:utf-8 from wsgiref.simple_server import make_server #引入wsgiref的make_server def RunServer(environ, start_response): #创建通讯内容函数 start_response('200 OK', [('Content-Type', 'text/html')]) #HTML方式返回内容 return '<h1>Hello, web!</h1>' #返回内容 if __name__ == '__main__': httpd = make_server('', 8082, RunServer) #设置访问端口,和通讯内容函数 httpd.serve_forever() #执行通讯函数
RunServer(environ, start_response)创建通讯内容函数,里面有两个参数
environ里面包含用户的请求信息如ip等
start_response里面包含返回信息
查看方式:
自定义Web框架
一、框架
通过python标准库提供的wsgiref模块开发一个自己的Web框架
根据用户访问的路径,给出相应的内容
#!/usr/bin/env python #coding:utf-8 from wsgiref.simple_server import make_server def index(): #函数返回字符串index return 'index' def login(): #login return 'login' URLS = { #设置一个字典,键为路径名称,值为函数名称 "/index":index, "/login":login, } def RunServer(environ, start_response): start_response('200 OK', [('Content-Type', 'text/html')]) url = environ['PATH_INFO'] #接收用户访问的路径名称 if url in URLS.keys(): #判断用户访问路径在URLS字典里是否存在 furl = URLS[url] #如果存在通过下标拿到字典里的函数名称 ret = furl() #执行函数赋值给ret变量,相当于ret等于函数返回字符串 else: ret = "404" #如果不存在ret变量等于404 return ret #最后将ret变量返回给浏览器 if __name__ == '__main__': httpd = make_server('', 8082, RunServer) httpd.serve_forever()
二、模板引擎,和MVC
MVC框架,就是归类后根据文件夹定义的名字
在上一步骤中,对于所有的login、index均返回给用户浏览器一个简单的字符串,在现实的Web请求中一般会返回一个复杂的符合HTML规则的字符串,所以我们一般将要返回给用户的HTML写在指定文件中,然后再返回。如:
模板引擎归类,归类就是为了以后方便管理
urls.py将映射文件信息写在这个文件里,以后要添加映射就在这里写
#!/usr/bin/env python #coding:utf-8 import controller # 映射文件 URLS = { #设置一个字典,键为路径名称,值为函数名称 "/index":controller.index, "/login":controller.login, }
controller.py逻辑处理文件,根据用户访问路径,给出对应的处理,以后要添加逻辑处理函数就写在这里
#!/usr/bin/env python #coding:utf-8 import os #引入os模块 # 映射文件对应的函数 def index(): #函数返HTML文件内容 f = open(os.path.join('views','index.html'),'r') #拼接路径,打开index.html data = f.read() #读出html文件内容 f.close() #关闭打开的文件 return data def login(): f = open(os.path.join('views', 'login.html'),'r') data = f.read() f.close() return data
start.py模板引擎启动文件,用于启动模板引擎,一般不做修改
#!/usr/bin/env python #coding:utf-8 from wsgiref.simple_server import make_server #导入wsgiref模块里的make_server方法 from urls import URLS #导入映射文件变量 def RunServer(environ, start_response): #定义RunServer函数,接收请求信息,和发送内容 start_response('200 OK', [('Content-Type', 'text/html')]) url = environ['PATH_INFO'] #接收用户访问的路径名称 if url in URLS.keys(): #判断用户访问路径在URLS字典里是否存在 furl = URLS[url] #如果存在通过下标拿到字典里的函数名称 ret = furl() #执行函数赋值给ret变量,相当于ret等于函数返回字符串 else: ret = "404" #如果不存在ret变量等于404 return ret #最后将ret变量返回给浏览器 if __name__ == '__main__': httpd = make_server('', 8082, RunServer) httpd.serve_forever()
views文件夹用于专门存放html文件
models文件夹用于专门存放数据库处理文件
整理后的结构
Web框架,一般根据存放数据库处理文件夹的首字母M,存放html文件夹首字母V,逻辑处理文件首字母C,来命名的,这就是mvc框架
Web框架运行图
Web框架请求动态内容
对于上述代码,虽然可以返回给用户HTML的内容以现实复杂的页面,但是还是存在问题:如何给用户返回动态内容?
1自定义一套特殊的语法,进行替换
html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <!--{{item}}设置一个表示--> <h1>{{item}}</h1> </body> </html>
逻辑处理文件controller.py
#!/usr/bin/env python #coding:utf-8 import os #引入os模块 import time #引入事件模块 # 映射文件对应的函数 def index(): #函数返HTML文件内容 f = open(os.path.join('views','index.html'),'r') #拼接路径,打开index.html data = f.read() #读出html文件内容 f.close() #关闭打开的文件 new_data = data.replace("{{item}}",str(time.time())) #获取系统时间转换成字符串,替换html里的{{item}} return new_data def login(): f = open(os.path.join('views', 'login.html'),'r') data = f.read() f.close() return data
2使用开源工具jinja2,遵循其指定语法
jinja2模块Web框架模块
Template()方法逻辑处理Web框架
render()方法设置html可调用python变量
encode()返回逻辑处理后的网页字符串给浏览器
首先需要安装jinja2第三方模块
逻辑处理文件controller.py
#!/usr/bin/env python #coding:utf-8 import os #引入os模块 from jinja2 import Template #引入jinja2模块 # 映射文件对应的函数 def index(): #函数返HTML文件内容 f = open(os.path.join('views','index.html'),'r') #拼接路径,打开index.html result = f.read() #读出html文件内容 f.close() # 关闭打开的文件 template = Template(result) #将读出的字符串传入jinja2模块的Template方法逻辑处理网页字符串 data = template.render(name='John Doe', user_list=['alex', 'eric']) #render方法向网页字符串添加python可以变量 return data.encode('utf-8') #返回逻辑处理后的字符串给浏览器 def login(): f = open(os.path.join('views', 'login.html'),'r') data = f.read() f.close() return data
html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>{{name}}</h1> <!--{{引用框架逻辑处理设置变量}}--> <ul> {% for item in user_list %} <!--{%可以远行代码块%}--> <li>{{item}}</li> {% endfor %} </ul> </body> </html>