[TOC]css
在了解python的三大web框架以前,咱们先本身动手实现一个。html
备注:前端
这部分重在掌握实现思路,代码不是重点python
代码中也有许多细节并未考虑,重在实现思路mysql
咱们通常是使用浏览器当作客户端,而后基于HTTP协议本身写服务端代码做为服务端jquery
先自行去回顾一下HTTP协议这一起的知识web
import socket server = socket.socket() # 基于socket通讯(TCP) server.bind(('127.0.0.1', 8080)) server.listen(5) while True: conn, addr = server.accept() data = conn.recv(2048) # 接收请求 print(str(data, encoding='utf-8')) conn.send(b'HTTP/1.1 200 OK\r\n\r\n') # 依据HTTP协议,发送响应给客户端(浏览器),这里是响应首行 + 响应头 + 空行 # response = bytes('<h3>这是响应内容</h3>', encoding='GBK') response = '<h3>这是响应内容</h3>'.encode('GBK') # 我电脑上是GBK编码,因此使用GBK编码将字符串转成二进制 conn.send(response) # 继续发送响应体 conn.close() # 断开链接(无状态、无链接) # 浏览器发过来的数据以下 ''' GET / HTTP/1.1 Host: 127.0.0.1:8080 Connection: keep-alive Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.90 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3 Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.9 Cookie: _qddaz=QD.w3c3g1.j2bfa7.jvp70drt; csrftoken=kJHVGICQOglLxJNiui0o0UyxNtR3cXbJPXqaUFs5FoxeezuskRO7jlQE0JNwYXJs GET /favicon.ico HTTP/1.1 Host: 127.0.0.1:8080 Connection: keep-alive User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.90 Safari/537.36 Accept: image/webp,image/apng,image/*,*/*;q=0.8 Referer: http://127.0.0.1:8080/ Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.9 Cookie: _qddaz=QD.w3c3g1.j2bfa7.jvp70drt; csrftoken=kJHVGICQOglLxJNiui0o0UyxNtR3cXbJPXqaUFs5FoxeezuskRO7jlQE0JNwYXJs '''
而后右键运行,在浏览器访问 127.0.0.1:8080
便可看到响应数据sql
关于启动服务器与页面请求(在我处理的时候,页面网络请求会常常处于 pending状态,不是很清楚缘由,通常这个状况下,直接重启一下服务器便可)数据库
上面的代码已经实现了基本请求响应,那如何根据不一样的请求做出不一样的响应呢?django
咱们输入不一样的url,看看服务器端会返回什么
分析请求
浏览器访问 http://127.0.0.1:8080/index GET /index HTTP/1.1 Host: 127.0.0.1:8080 Connection: keep-alive Cache-Control: max-age=0 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.90 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3 Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.9 Cookie: _qddaz=QD.w3c3g1.j2bfa7.jvp70drt; csrftoken=kJHVGICQOglLxJNiui0o0UyxNtR3cXbJPXqaUFs5FoxeezuskRO7jlQE0JNwYXJs 浏览器访问 http://127.0.0.1:8080/home GET /home HTTP/1.1 Host: 127.0.0.1:8080 Connection: keep-alive Cache-Control: max-age=0 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.90 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3 Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.9 Cookie: _qddaz=QD.w3c3g1.j2bfa7.jvp70drt; csrftoken=kJHVGICQOglLxJNiui0o0UyxNtR3cXbJPXqaUFs5FoxeezuskRO7jlQE0JNwYXJs
原来请求首行的 GET 后面跟的就是请求咱们想要信息(/index 首页、/home 家)
这些信息也是咱们接收到的(data = conn.recv(2048)
print(str(data, encoding='utf-8'))
),那可不能够取出来,根据值的不一样做不一样处理呢?
处理请求,获取 url
data = '''GET /home HTTP/1.1 Host: 127.0.0.1:8080 Connection: keep-alive Cache-Control: max-age=0 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.90 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3 Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.9 Cookie: _qddaz=QD.w3c3g1.j2bfa7.jvp70drt; csrftoken=kJHVGICQOglLxJNiui0o0UyxNtR3cXbJPXqaUFs5FoxeezuskRO7jlQE0JNwYXJs''' print(data.split('\n')[0].split(' ')[1]) # ... ---> GET /home HTTP/1.1 --> ['GET', '/home', 'HTTP/1.1'] --> /home # /home
依据上述切割规则,咱们来对不一样的请求做出不一样的响应
import socket server = socket.socket() server.bind(('127.0.0.1', 8080)) server.listen(5) while True: conn, addr = server.accept() data = conn.recv(2048).decode('utf-8') data = data.split('\n')[0].split(' ')[1] print(data) conn.send(b'HTTP/1.1 200 OK\r\n\r\n') if data == '/index': response = '<h3>这里是 index...</h3>'.encode('GBK') elif data == '/home': response = '<h3>这里是 home...</h3>'.encode('GBK') else: response = '<h3>404 NOT FOUND...\n找不到您要找的资源...</h3>'.encode('GBK') conn.send(response) conn.close() # --- 浏览器请求 http://127.0.0.1:8080/index 的打印信息 # /index # /favicon.ico # --- 浏览器请求 http://127.0.0.1:8080/home 的打印信息 # /home # /favicon.ico # --- 浏览器请求 http://127.0.0.1:8080/de2332f 的打印信息 # /de2332f # /favicon.ico
页面成功显示不一样的信息
http://127.0.0.1:8080/index
http://127.0.0.1:8080/home
http://127.0.0.1:8080/de2332f
404页面也应该算做设计网站的一部分,能够给人不同的感受
前面处理 scoket 和 http 的那堆代码一般是不变的,且与业务逻辑没什么关系,若是每一个项目都要写一遍,那岂不是很麻烦?那封装成模块嘛~
不过这个操做已经有人帮咱们作了,而且封装的更增强大,就是 wsgiref 模块
conn.send(b'HTTP/1.1 200 OK\r\n\r\n')
了),返回给服务端from wsgiref.simple_server import make_server # 导模块 def run(env, response): """ 先无论这里的 env 和 response 什么个状况 env:是请求相关的数据,wsgiref帮咱们把请求包装成了一个大字典,方便取值 response:是响应相关的数据 """ response('200 OK', []) print(env) current_path = env.get('PATH_INFO') print(current_path) if current_path == '/index': return ['hello, there is index...'.encode('utf-8')] elif current_path == '/login': return ['hello, there is login...'.encode('utf-8')] else: return ['sorry... that pages you want is not found...'.encode('utf-8')] if __name__ == '__main__': # 实时监测 127.0.0.1:8080 地址,一旦有客户端链接,会自动加括号调用 run 方法 server = make_server('127.0.0.1', 8080, run) server.serve_forever() # 启动服务器 # /index # ---> env 的数据(手动删减了一些),能够看到其中有个 PATH_INFO 是咱们要的东西(还有浏览器版本啊,USER-AGENT啊,客户端系统环境变量啊之类的信息) '''{'ALLUSERSPROFILE': 'C:\\ProgramData', ...省略部分... , 'COMSPEC': 'C:\\Windows\\system32\\cmd.exe', 'PROCESSOR_IDENTIFIER': 'Intel64 Family 6 Model 60 Stepping 3, GenuineIntel', 'PROCESSOR_LEVEL': '6', 'PROCESSOR_REVISION': '3c03', 'PYTHONIOENCODING': 'UTF-8', 'SESSIONNAME': 'Console', 'SYSTEMDRIVE': 'C:', 'SERVER_PORT': '8080', 'REMOTE_HOST': '', 'CONTENT_LENGTH': '', 'SCRIPT_NAME': '', 'SERVER_PROTOCOL': 'HTTP/1.1', 'SERVER_SOFTWARE': 'WSGIServer/0.2', 'REQUEST_METHOD': 'GET', 'PATH_INFO': '/index', 'QUERY_STRING': '', 'REMOTE_ADDR': '127.0.0.1', 'CONTENT_TYPE': 'text/plain', 'HTTP_HOST': '127.0.0.1:8080', 'HTTP_CONNECTION': 'keep-alive', 'HTTP_UPGRADE_INSECURE_REQUESTS': '1', 'HTTP_USER_AGENT': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.90 Safari/537.36', 'HTTP_ACCEPT': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3', csrftoken=kJHVGICQOglLxJNiui0o0UyxNtR3cXbJPXqaUFs5FoxeezuskRO7jlQE0JNwYXJs', mode='w' encoding='UTF-8'>, 'wsgi.version': (1, 0), }'''
伏笔
服务端代码、路由配置、视图函数,照目前的写法全都冗在一起,后期功能扩展时,这个文件会变得很长,不方便维护,因此选择把他拆分开来
就是将服务端代码拆分红以下三部分:
server.py 放服务端代码
urls.py 放路由与视图函数对应关系
views.py 放视图函数/类(处理业务逻辑)
views.py
def index(env): return 'index' def login(env): return 'login'
urls.py
from views import * urls = [ ('/index', index), ('/login', login), ]
server.py
from wsgiref.simple_server import make_server # 导模块 from urls import urls # 引入 urls.py 里的 urls列表(命名的不是很规范) def run(env, response): response('200 OK', []) current_path = env.get('PATH_INFO') func = None for url in urls: if current_path == url[0]: func = url[1] break if func: res = func(env) else: res = '404 Not Found.' return [res.encode('utf-8')] # 注意这里返回的是一个列表(可迭代对象才行),wsgiref 模块规定的,可能还有其余的用途吧 if __name__ == '__main__': server = make_server('127.0.0.1', 8080, run) server.serve_forever()
通过上面的拆分后,后续想要支持其余 url,只须要在 urls.py 中添加一条对应关系,在 views.py 中把该函数实现,重启服务器便可访问
以支持 http://127.0.0.1:8080/new_url
访问为例
urls.py
from views import * urls = [ ('/index', index), ('/login', login), ('/new_url', new_url), ]
views.py
def index(env): return 'index' def login(env): return 'login' def new_url(env): # 这里能够写一堆逻辑代码 return 'new_url'
重启服务器,打开浏览器便可访问 http://127.0.0.1:8080/new_url
扩展性高了不少,且逻辑更清晰了,更不容易弄错(框架的好处提现,也是为何脱离了框架不会写的缘由,这块代码写的太少,不经常使用到,没了框架又写不出来)
前面写了那么多,都只是一直在返回纯文本信息,而咱们通常请求页面返回的都是浏览器渲染好的华丽的页面,那要怎么放回华丽的页面呢?
页面嘛,就是 HTML + CSS + JS 渲染出来的,因此咱们也能够把 HTML文件当成数据放在响应体里直接返回回去
新建一个功能的步骤仍是复习一下
- 在 urls.py 里面加一条路由与视图函数的对应关系
- 在 views.py 里面加上那个视图函数,并写好内部逻辑代码
- 重启服务器,浏览器打开页面访问
这里我们就接着上面的 new_url 写,用他来返回 一个网页
新建一个 templates 文件夹,专门用来放 HTML 文件
templates/new_url.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>New URL</h1> <h5>Wellcome!</h5> </body> </html>
views.py
def index(env): return 'index' def login(env): return 'login' def new_url(env): # 读取并把 new_url 文件返回给客户端(浏览器) with open(r'templates/new_url.html', 'rb') as f: html_data = f.read() return html_data.decode('utf-8') # 由于 run 函数那里作了 encode, 而二进制数据没有 encode这个方法,因此这里先解码一下,而后那边再编码一下
重启服务器,使用浏览器访问
上面提到了静态页面,那什么是静态页面?什么又是动态页面呢?
**静态网页:**纯html网页,数据是写死的,全部同url的请求拿到的数据都是同样的
**动态网页:**后端数据拼接,数据不是写死的,是动态拼接的,好比:
后端实时获取当前时间“传递”(塞)给前端页面展现
后端从数据库获取数据“传递”给前端页面展现
要怎么在 html 里插入时间呢?
往 html 里的插入?那替换好像也能够达到效果啊?
html_data = f.read()
? 好像 html 被读出出来了,并且仍是二进制的,二进制能够 decode 变成字符串,字符串有 replace方法能够替换字符串,那我随便在网页里写点内容,而后替换成时间?
先把基础歩鄹作好
templates/get_time.html 编写展现页面
put_times_here 用来作占位符,一下子给他替换成时间
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>北京时间:</h1> <h1>put_time_here</h1> </body> </html>
urls.py 路由与视图函数对应关系
from views import * urls = [ ('/index', index), ('/login', login), ('/new_url', new_url), ('/get_time', get_time), ]
views.py 实现视图函数
def index(env): return 'index' def login(env): return 'login' def new_url(env): # 读取并把 new_url 文件返回给客户端(浏览器) with open(r'templates/new_url.html', 'rb') as f: html_data = f.read() return html_data def get_time(env): # 读取并把 get_time 文件返回给客户端(浏览器) with open(r'templates/get_time.html', 'rb') as f: html_data = f.read().decode('utf-8') import time html_data = html_data.replace('put_time_here', time.strftime("%Y-%m-%d %X")) return html_data
重启服务器并打开浏览器访问 http://127.0.0.1:8080/get_time
关键思路:至关于占位符,字符串替换,后期把前端要替换的字符的格式统一规定下,方便阅读与统一处理,这其实也就是目前的模版语法的雏形
咱们只须要把处理好的字符串(HTML格式的)返回给浏览器,待浏览器渲染便可有页面效果
jinja2模块有着一套 模板语法,能够帮我更方便地在 html 写代码(就想写后台代码同样),让前端也可以使用后端的一些语法操做后端传入的数据
jinja2 并非 python 解释器自带的,因此须要咱们本身安装
因为 flask 框架是依赖于 jinja2 的,所下载 flask 框架也会自带把 jinja2 模块装上
命令行执行,pip3 install jinja2
或图形化操做安装(参考 Django 的安装方法)
这里只是知道有模板语法这么一个东西可让咱们很方便的往 html 写一些变量同样的东西,并不会讲 jinja2 的语法,后续会有的
urls.py
from views import * urls = [ ('/index', index), ('/login', login), ('/new_url', new_url), ('/get_time', get_time), ('/show_dic', show_dic), ]
views.py
def index(env): return 'index' def login(env): return 'login' def new_url(env): # 读取并把 new_url 文件返回给客户端(浏览器) with open(r'templates/new_url.html', 'rb') as f: html_data = f.read() return html_data def get_time(env): # 读取并把 get_time 文件返回给客户端(浏览器) with open(r'templates/get_time.html', 'rb') as f: html_data = f.read().decode('utf-8') import time html_data = html_data.replace('put_time_here', time.strftime("%Y-%m-%d %X")) return html_data def show_dic(env): user = { "username": "jason", "age": 18, } with open(r'templates/show_dic.html', 'rb') as f: html_data = f.read() # 使用 jinja2 的模板语法来将数据渲染到页面上(替换占位符) from jinja2 import Template tmp = Template(html_data) res = tmp.render(dic=user) # 将字典 user 传递给前端页面,前端页面经过变量名 dic 就可以获取到该字典 return res
templates/show_dic.html 写页面
jinja2 给字典扩展了点语法支持({{ dic.username }}
)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>Nice to meet you~ i'm {{ dic.username }} , and i'm {{ dic.age }} years old.</h1> <p>username: {{ dic['username']}}</p> <p>age: {{ dic.get('age')}}</p> </body> </html>
重启服务器并打开浏览器访问 http://127.0.0.1:8080/show_dic
为何说动态?
若是你改变了字典里的值,那么请求这个页面,显示的数据也会跟着改变(注意这个字典通常都是其余地方获取过来的)
模板语法(贴近python语法): 前端也可以使用后端的一些语法操做后端传入的数据 {{data.password}} # jinja2 多给字典作了 点语法支持 ... 其余的语法,写法 for 循环 {%for user_dict in user_list%} <tr> <td>{{user_dict.id}}</td> <td>{{user_dict.name}}</td> <td>{{user_dict.password}}</td> </tr> {%endfor%}
思路
pymsql 从数据库取数据(指定成 列表套字典 的格式(DictCursor)) 后台 python 代码处理数据 交由 jinja2 模块语法渲染到 html 页面上 数据条数不定怎么办? 有多少条记录就显示多少条呗...循环? 表格格式先写好,而后循环渲染数据到标签上(特定语法表示循环)
建立数据库 django_test_db,而后执行以下 SQL 命令
/* Navicat MySQL Data Transfer Source Server : localhost-E Source Server Type : MySQL Source Server Version : 50645 Source Host : localhost:3306 Source Schema : django_test_db Target Server Type : MySQL Target Server Version : 50645 File Encoding : 65001 Date: 15/09/2019 00:41:09 */ SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0; -- ---------------------------- -- Table structure for user_info -- ---------------------------- DROP TABLE IF EXISTS `user_info`; CREATE TABLE `user_info` ( `id` int(11) NOT NULL AUTO_INCREMENT, `username` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, `password` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact; -- ---------------------------- -- Records of user_info -- ---------------------------- INSERT INTO `user_info` VALUES (1, 'jason', '123'); INSERT INTO `user_info` VALUES (2, 'tank', '123'); INSERT INTO `user_info` VALUES (3, 'jerry', '123'); INSERT INTO `user_info` VALUES (4, 'egon', '456'); SET FOREIGN_KEY_CHECKS = 1;
urls.py
from views import * urls = [ ('/index', index), ('/login', login), ('/new_url', new_url), ('/get_time', get_time), ('/show_dic', show_dic), ('/get_users', get_users), ]
views.py
def index(env): return 'index' def login(env): return 'login' def new_url(env): # 读取并把 new_url 文件返回给客户端(浏览器) with open(r'templates/new_url.html', 'rb') as f: html_data = f.read() return html_data def get_time(env): # 读取并把 get_time 文件返回给客户端(浏览器) with open(r'templates/get_time.html', 'rb') as f: html_data = f.read().decode('utf-8') import time html_data = html_data.replace('put_time_here', time.strftime("%Y-%m-%d %X")) return html_data def show_dic(env): user = { "username": "jason", "age": 18, } with open(r'templates/show_dic.html', 'rb') as f: html_data = f.read() # 使用 jinja2 的模板语法来将数据渲染到页面上(替换占位符) from jinja2 import Template tmp = Template(html_data) res = tmp.render(dic=user) # 将字典 user 传递给前端页面,前端页面经过变量名 dic 就可以获取到该字典 return res # 先写个空函数在这里占位置,去把 pymysql 查数据的写了再过来完善 def get_users(env): # 从数据库取到数据 import op_mysql user_list = op_mysql.get_users() with open(r'templates/get_users.html', 'r', encoding='utf-8') as f: html_data = f.read() from jinja2 import Template # 其实这个引入应该放在页面最上方去的,但为了渐进式演示代码推动过程,就放在这里了 tmp = Template(html_data) res = tmp.render(user_list=user_list) return res
**op_mysql.py **若是你的配置不同要本身改过来
import pymysql def get_cursor(): server = pymysql.connect( # 根据本身电脑上 mysql 的状况配置这一块的内容 host='127.0.0.1', port=3306, user='root', password='000000', charset='utf8', # 千万注意这里是 utf8 ! database='django_test_db', autocommit=True ) cursor = server.cursor(pymysql.cursors.DictCursor) return cursor def get_users(): cursor = get_cursor() # 链接数据库 sql = "select * from user_info" # 把用户的全部信息查出来(通常不会把密码放回给前端的,这里只是为了作演示) affect_rows = cursor.execute(sql) user_list = cursor.fetchall() return user_list
templates/get_users.html 用户信息展现页面
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <!-- 引入jquery bootstrap 文件的 CDN --> <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script> <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet"> <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script> </head> <body> <div class="container"> <div class="row"> <div class="col-md-8 col-md-offset-2"> <h2 class="text-center">用户数据展现</h2> <table class="table table-hover table-bordered table-striped"> <thead> <tr> <th>id</th> <th>username</th> <th>password</th> </tr> </thead> <tbody> <!-- jinja2 的模版语法(for循环) --> {%for user_dict in user_list%} <tr> <td>{{user_dict.id}}</td> <td>{{user_dict.username}}</td> <td>{{user_dict.password}}</td> </tr> {%endfor%} </tbody> </table> </div> </div> </div> </body> </html>
用浏览器访问 http://127.0.0.1:8080/get_users
,重启服务器,在切回浏览器便可看到页面效果
1.纯手撸web框架 1.手动书写socket代码 2.手动处理http数据 2.基于wsgiref模块帮助咱们处理scoket以及http数据(顶掉上面的歩鄹) wsgiref模块 1.请求来的时候 解析http数据帮你打包成一个字典传输给你 便于你操做各项数据 2.响应走的时候 自动帮你把数据再打包成符合http协议格式的样子 再返回给前端 3.封装路由与视图函数对应关系 以及视图函数文件 网站用到的全部的html文件所有放在了templates文件夹下 1.urls.py 路由与视图函数对应关系 2.views.py 视图函数 (视图函数不仅仅指函数 也能够是类) 3.templates 模板文件夹 4.基于jinja2实现模板的渲染 模板的渲染 后端生成好数据 经过某种方式传递给前端页面使用(前端页面能够基于模板语法更加快捷简便使用后端传过来的数据)
在不知道是要 encode 仍是 decode 的时候,能够用一下方法
二进制数据对应的确定是 decode 解码 成字符串呀
字符串对应的确定是 encode 编码成二进制数据呀
数据类型转换技巧(处理编码)(数据 + encoding)
# 转成 bytes 类型 bytes(data, encoding='utf-8') # 转成 str 类型 str(data, encoding='utf-8')
大而全,自带的功能特别特别多,就相似于航空母舰
**缺点:**有时过于笨重(小项目不少用不到)
短小精悍,自带的功能特别少,全都是依赖于第三方组件(模块)
第三方组件特别多 --> 若是把全部的第三方组件加起来,彻底能够盖过django
**缺点:**比较受限于第三方的开发者(可能有bug等)
天生的异步非阻塞框架,速度特别快,可以抗住高并发
能够开发游戏服务器(但开发游戏,仍是 C 和C++用的多,执行效率更快)
前面的手撸推导过程,整个框架过程大体能够分为如下三部分
A:socket处理请求的接收与响应的发送
B:路由与视图函数
C:模板语法给动态页面渲染数据
A:用的<u>别人</u>的 wsgiref 模块 B:自带路由与视图函数文件 C:自带一套模板语法
A:用的<u>别人</u>的werkzeug 模块(基于 wsgiref 封装的) B:自带路由与视图函数文件 C:用的<u>别人</u>的jinja2
A,B,C全都有本身的实现
参见个人另外一篇博客:Django-下载安装-配置-建立django项目-三板斧简单使用
原文出处:https://www.cnblogs.com/suwanbin/p/11520959.html