1.简介
web框架的本质:socket服务端与浏览器的通信 socket服务端功能划分: 1.负责与浏览器收发消息(socket通信) --》wsgiref/uWsgi/gunicorn等web服务网关接口和服务器 2.根据用户访问不同的路径执行不同的函数 --》路由系统(url与函数的对应关系) 3.从HTML读取出内容并且完成字符串的替换 --》jinja2(模板语言)
2.静态网站
""" 这是一个静态的web网站,返回什么数据类型就是什么,而现在网站都是动态的。 """ import socket def f1(request): """ 处理用户请求,并返回相应的内容 :param request: 用户请求的所有信息 :return: """ # 读取本地二进制文件并返回(在这里是自己写模板,可以任意后缀名文件并不一定需要html后缀) f = open('index.fsw','rb') data = f.read() f.close() return data def f2(request): f = open('aricle.tpl','rb') data = f.read() f.close() return data # 路由与函数的对应关系(路由系统) routers = [ ('/xxx', f1), ('/ooo', f2), ] def run(): # 获取socket对象 sock = socket.socket() # 绑定ip地址和端口 sock.bind(('127.0.0.1',8080)) # 开始监听(设置最大监听数5个) sock.listen(5) while True: conn,addr = sock.accept() # 夯住,等待用户连接 # 获取用户发送的数据 data = conn.recv(8096) # 直接转换为字符串 data = str(data,encoding='utf-8') print(data) # 根据http协议划分请求头和请求体 headers,bodys = data.split(' ') # 根据已有的http协议数据结构切分元素 temp_list = headers.split(' ') # 分别获取请求方法、请求url地址、请求协议类型 method,url,protocal = temp_list[0].split(' ') conn.send(b"HTTP/1.1 200 OK ") func_name = None # 设置标志位 for item in routers: # 遍历url与函数对应关系表,并判断当前请求url是否相等 if item[0] == url: # 能对应就获取函数名并停止循环 func_name = item[1] break if func_name: # 有这个函数就加括号调用并传入参数 response = func_name(data) else: response = b"404" # 返回函数处理后的结果 conn.send(response) conn.close() if __name__ == '__main__': run()
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <table border="1"> <thead> <tr> <th>ID</th> <th>用户名</th> <th>邮箱</th> </tr> </thead> <tbody> <tr> <th>1</th> <th>root</th> <th>root@qq.com</th> </tr> </tbody> </table> </body> </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <h1>用户登录</h1> <form> <p><input type="text" placeholder="用户名" /></p> <p><input type="password" placeholder="密码" /></p> </form> </body> </html>
3.动态网站
"""动态网站则是在静态网站的基础之上,进行字符串的替换,以完成网站页面的实时更新效果""" import socket def f1(request): """ 处理用户请求,并返回相应的内容 :param request: 用户请求的所有信息 :return: """ f = open('index.fsw','rb') data = f.read() f.close() return data def f2(request): """ 运用时间戳的方式,初步实现动态网站 :param request: :return: """ f = open('aricle.tpl','r',encoding='utf-8') data = f.read() f.close() import time # 获取时间戳 ctime = time.time() # 调用字符串的replace()替换方法换成时间戳,页面每次刷新显示的数据都不一样 data = data.replace('@@sw@@',str(ctime)) # 返回bytes()类型数据 return bytes(data,encoding='utf-8') def f3(request): """ 获取数据库数据,只要数据库数据有更新,则页面刷新之后都会显示 :param request: 用户请求的信息 :return: """ import pymysql # 创建连接对象 conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='yang123', db='yangyu') # 获取游标 cursor = conn.cursor(cursor=pymysql.cursors.DictCursor) # 执行sql语句查询数据库数据 cursor.execute("select id,username,password from userinfo") # 获取表中所有数据 user_list = cursor.fetchall() # 关闭游标对象 cursor.close() # 关闭连接对象 conn.close() content_list = [] for row in user_list: # 遍历数据库查询的数据,拼接字符串 tp = "<tr><td>%s</td><td>%s</td><td>%s</td></tr>" %(row['id'],row['username'],row['password']) # 把拼接的字符串添加到列表 content_list.append(tp) # 调用.join方法把列表转换为字符串 content = "".join(content_list) f = open('userlist.html','r',encoding='utf-8') template = f.read() f.close() # 模板渲染(模板+数据)完成字符串的替换 data = template.replace('@@sdfsdffd@@',content) return bytes(data,encoding='utf-8') def f4(request): """ 调用第三方模块,实现页面模板的渲染 :param request: :return: """ import pymysql # 创建连接对象 conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='yang123', db='yangyu') # 获取游标 cursor = conn.cursor(cursor=pymysql.cursors.DictCursor) # 执行sql语句查询数据库数据 cursor.execute("select id,username,password from userinfo") # 获取表中所有数据 user_list = cursor.fetchall() # 关闭游标对象 cursor.close() # 关闭连接对象 conn.close() f = open('hostlist.html','r',encoding='utf-8') data = f.read() f.close() # 基于第三方工具实现的模板渲染 from jinja2 import Template template = Template(data) # 调用render()方法完成字符串的替换,这里要注意,前后端特殊语法要相同 data = template.render(user_list=user_list,user='sdfsdfsdf') return data.encode('utf-8') # 路由与函数的对应关系 routers = [ ('/xxx', f1), ('/ooo', f2), ('/userlist.htm', f3), ('/host.html', f4), ] def run(): # 获取socket对象 sock = socket.socket() # 绑定ip地址和端口 sock.bind(('127.0.0.1',8080)) # 开始监听(设置最大监听数5个) sock.listen(5) while True: conn,addr = sock.accept() # 夯住,等待用户连接 # 获取用户发送的数据 data = conn.recv(8096) # 直接转换为字符串 data = str(data,encoding='utf-8') # 根据http协议划分请求头和请求体 headers,bodys = data.split(' ') # 根据已有的http协议数据结构切分元素 temp_list = headers.split(' ') # 分别获取请求方法、请求url地址、请求协议类型 method,url,protocal = temp_list[0].split(' ') conn.send(b"HTTP/1.1 200 OK ") func_name = None # 设置标志位 for item in routers: # 遍历url与函数对应关系表,并判断当前请求url是否相等 if item[0] == url: # 能对应就获取函数名并停止循环 func_name = item[1] break if func_name: # 有这个函数就加括号调用并传入参数 response = func_name(data) else: response = b"404" # 返回函数处理后的结果 conn.send(response) conn.close() if __name__ == '__main__': run()
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <table border="1"> <thead> <tr> <th>ID</th> <th>用户名</th> <th>邮箱</th> </tr> </thead> <tbody> <tr> <th>1</th> <!-- 自定义字符串替换的特殊语法 --> <th>@@sw@@</th> <th>root@qq.com</th> </tr> </tbody> </table> </body> </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <table border="1"> <thead> <tr> <th>ID</th> <th>用户名</th> <th>邮箱</th> </tr> </thead> <tbody> {% for row in user_list %} <!--使用第三方模板,就要遵循他的语法规则--> <tr> <td>{{row.id}}</td> <td>{{row.username}}</td> <td>{{row.password}}</td> </tr> {% endfor %} </tbody> </table> {{user}} </body> </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <h1>用户登录</h1> <form> <p><input type="text" placeholder="用户名" /></p> <p><input type="password" placeholder="密码" /></p> </form> </body> </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <table border="1"> <thead> <tr> <th>ID</th> <th>用户名</th> <th>邮箱</th> </tr> </thead> <tbody> <!--自定义模板特殊语法--> @@sdfsdffd@@ </tbody> </table> </body> </html>
4.总结
有以上我们模拟网站(socket服务端)和浏览器(socket客户端)的知识知道了: 1.http是建立在tcp之上的,无状态的,短链接,一次请求一次响应。 而TCP是不断开的长连接。 2.http协议是固定的键值对组合,每个键值对之间由 分割,请求头和请求体之间则是由两个 分割。而响应头和响应体也是这样的组合。 3.自己写的网站必须具备以下要素: a.socket服务端 b.根据url的不同,返回不同的内容(url与函数的对应关系) c.返回字符串给用户(模板引擎渲染:HTML充当模板和特殊字符,自己定义任意数据) 而web框架的种类也是根据以上三点相结合: 框架自带a,b,c Tornado [第三方a],b,c wsgiref服务网关接口、Django [第三方a],b,[第三方c] wsgiref服务网关接口、Flask、jinja2模板 按照另一种维度划分: 重量级:Django 轻量级:Tornado、Flask