一、web框架介绍:
什么是web框架:
所有的web应用本质上就是一个socket服务端,而用户的浏览器就是一个socket客户端。这样就可以实现web框架了。
import socket sk = socket.socket() sk.bind(("127.0.0.1", 80)) sk.listen(5) while True: conn, addr = sk.accept() data = conn.recv(8096) conn.send(b"OK") conn.close()
总而言之web框架的原理就是这短短的十几行代码,当然用户浏览器向服务端发送数据怎么发,这个怎么定如果谁都能定岂不是乱套了,各有各的规则了,所以就有一个统一的规则,收发数据时候规定了格式,不能随便写,这就是HTTP协议,不管是收数据还是发数据都要按照这个协议的规则来。
如果想详细了解HTTP:请点击这里
每个HTTP都包含Header和Body两部分,其中Body是可选的,HTTP响应的响应头(Header)中有content_Type表明响应内容格式。如果响应的是网页,则content-Type的值为text/html
HTTP的请求方式:
GET:
GET /path HTTP/1.1
header1:v1
header2:v2
POST:
POST /path HTTP/1.1
header1:v1
header2:v2
请求体...
当遇到 时,表示响应头结束了,以 后的数据全属于响应体。
import socket sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.bind(('127.0.0.1', 8000)) sock.listen(5) while True: conn, addr = sock.accept() data = conn.recv(8096) conn.send(b"HTTP/1.1 200 OK ") #此行为响应头 conn.send(b"OK") #此行为响应体 conn.close() #这样就给简单的socket加上了HTTP规则,这样就算实现了一个web框架了
通过上面用socket实现的简单的web框架足以说明,作为web框架一般分为两个部分:服务程序和应用程序。服务器其实就是起到对socket的封装,并在请求来时对请求的各种数据进行整理。常见的web:Django、Flask、web.py,不同的框架开发方式不同,但是它们开发的应用程序都要和服务器程序配合使用。
由于框架有多种,服务器程序就需要提供多种不同的支持,这样的话局面会有点混乱,而能给这种情况整一个标准吗?当然有标准啦有了标准框架和服务器都支持这个标准,这样就可以配合工作了,这个标准这么厉害,它是什么呢?
它就是传说中的WSGI(Web Server Gateway Interface)它就是一种规范,它定义使用Python编写的web应用程序与web服务器程序之间的接口格式,实现应用于服务器程序间的解耦
常用的WSGI服务器有uwsgi、Gunicorn而Python标准库的独立WSGI服务器叫wsgiref,django就是用这个模块来做服务器的。
例如: from wsgiref.simple_server import make_server def run_server(environ, start_response): start_response('200 OK', [('Content-Type', 'text/html;charset=utf8')]) # 设置HTTP响应的状态码和头信息 return [bytes("<h1>Hello world!</h1>", encoding="utf8"),] if __name__ == '__main__': httpd = make_server('', 8000, run_server) print("Serving HTTP on port 8000...") httpd.serve_forever()
这样的话是不是有点太简单了点?这也是太简易了,导致用户输入url是无法对url进行处理,那能不能改进一下来接收并处理用户输入的url请求呢
改进版的简易框架:
from wsgiref.simple_server import make_server def run_server(environ, start_response): start_response('200 OK', [('Content-Type', 'text/html;charset=utf8'), ]) # 设置HTTP响应的状态码和头信息 url = environ['PATH_INFO'] # 取到用户输入的url if url == "/index/": return [bytes("<h1>这是index页面</h1>", encoding="utf8"), ] elif url == "/home/": return [bytes("<h1>这是home页面</h1>", encoding="utf8"), ] else: return [bytes("404没有该页面", encoding="utf8"), ] if __name__ == '__main__': httpd = make_server('', 8000, run_server) print("Serving HTTP on port 8000...") httpd.serve_forever()
这不就解决了用户输入URL的问题了吗,但是问题又来了,如果有很多页面呢,挨个判断吗?那也太麻烦了吧,当然会有更好的方法了:
from wsgiref.simple_server import make_server def index(): with open("index.html", "rb") as f: data = f.read() return [data, ] def home(): with open("home.html", "rb") as f: data = f.read() return [data, ] # 定义一个url和函数的对应关系 URL_LIST = [ ("/index/", index), ("/home/", home), ] def run_server(environ, start_response): start_response('200 OK', [('Content-Type', 'text/html;charset=utf8'), ]) # 设置HTTP响应的状态码和头信息 url = environ['PATH_INFO'] # 取到用户输入的url func = None # 将要执行的函数 for i in URL_LIST: if i[0] == url: func = i[1] # 去之前定义好的url列表里找url应该执行的函数 break if func: # 如果能找到要执行的函数 return func() # 返回函数的执行结果 else: return [bytes("404没有该页面", encoding="utf8"), ] if __name__ == '__main__': httpd = make_server('', 8000, run_server) print("Serving HTTP on port 8000...") httpd.serve_forever()
这不是及解决了不用url全都拿来判断,而且将整个html返回给浏览器了,服务器先打开HTML文件,将其转换为二进制,然后发给浏览器。
这个页面是不是都写死了啊,那我要在页面上显示一些别的数据咋办呢?整个html文件换掉有点费事吧;怎样解决呢是不是需要做一个动态的HTML呢,那该怎样做呢
这时候我们需要引进一个新的模块:jinja2
jinja2的作用:利用一些特殊的符号来替换要展示的数据,这些特殊符号就是通过ji9nja2来渲染的,说白了jinja2就是一个渲染页面的工具。
下载安装jinja2:
pip install jinja2
举例说明:

<!DOCTYPE html> <html lang="zh-CN"> <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>姓名:{{name}}</h1> <h1>爱好:</h1> <ul> {% for hobby in hobby_list %} <li>{{hobby}}</li> {% endfor %} </ul> </body> </html>

from wsgiref.simple_server import make_server
from jinja2 import Template
def index():
with open("index2.html", "r") as f:
data = f.read()
template = Template(data) # 生成模板文件
ret = template.render({"name": "Alex", "hobby_list": ["烫头", "泡吧"]}) # 把数据填充到模板里面
return [bytes(ret, encoding="utf8"), ]
def home():
with open("home.html", "rb") as f:
data = f.read()
return [data, ]
# 定义一个url和函数的对应关系
URL_LIST = [
("/index/", index),
("/home/", home),
]
def run_server(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html;charset=utf8'), ]) # 设置HTTP响应的状态码和头信息
url = environ['PATH_INFO'] # 取到用户输入的url
func = None # 将要执行的函数
for i in URL_LIST:
if i[0] == url:
func = i[1] # 去之前定义好的url列表里找url应该执行的函数
break
if func: # 如果能找到要执行的函数
return func() # 返回函数的执行结果
else:
return [bytes("404没有该页面", encoding="utf8"), ]
if __name__ == '__main__':
httpd = make_server('', 8000, run_server)
print("Serving HTTP on port 8000...")
httpd.serve_forever()
对于去数据我们总不能一直把数据写在py文件中吧,我们是不是需要用数据库来存数据呢,数据库怎么用呢

#一定记着首先要导入 import pymysql conn = pymysql.connect(host="127.0.0.1", port=3306, user="root", passwd="xxx", db="xxx", charset="utf8")'''这里里是配置数据库用户名,密码,数据库名''' cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)#这儿是将查出的数据转换为字典形式 cursor.execute("select name, age, department_id from userinfo") #这里是执行sql语句,可以将SQL语句写在外面赋值给变量,这里面只写变量名 user_list = cursor.fetchall() cursor.close() conn.close()
模板的原理就是字符串替换,我们只要在HTML页面中遵循jinja2的语法法则写上,其内部就会按照制定语法进行相应的替换,从而达到动态的返回内容