15_Web框架-mini frame
1.WSGI协议概述(Python Web Server Gateway Interface)
1.WSGI允许开发者将选择web框架和web服务器分开,可以混合匹配web服务器和web框架,选择一个适合的配对
2.WSGI协议在不修改服务器和架构代码情况下确保了可以在多个架构下运行web服务器
3.Web服务器必须具备WSGI接口,所有的现代Python Web框架都已具备WSGI接口
4.WSGI接口让开发者不对代码作修改就能使服务器和特点的Web框架协同工作
5.浏览器请求WSGI_Server响应流程图: https://www.processon.com/view/link/5efcac3507912929cb6b33df
2.定义WSGI接口
def application(environ, start_response):
"""遵循WSGI标准的HTTP处理函数 :param environ: 一个包含所有HTTP请求信息的dict对象
:param start_response: 一个发送HTTP响应的函数
:return: 返回body信息
"""
start_response('200 OK', [('Content-Type', 'text/html')])
return 'Hello World!'
3.Web服务器-WSGI协议-web框架传递的字典
{
'HTTP_ACCEPT_LANGUAGE': 'zh-cn',
'wsgi.file_wrapper': <built-infunctionuwsgi_sendfile>,
'HTTP_UPGRADE_INSECURE_REQUESTS': '',
'uwsgi.version': b'2.0.15',
'REMOTE_ADDR': '172.16.7.1',
'wsgi.errors': <_io.TextIOWrappername=2mode='w'encoding='UTF-8'>,
'wsgi.version': (1,0),
'REMOTE_PORT': '',
'REQUEST_URI': '/',
'SERVER_PORT': '',
'wsgi.multithread': False,
'HTTP_ACCEPT': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'HTTP_HOST': '172.16.7.152: 8000',
'wsgi.run_once': False,
'wsgi.input': <uwsgi._Inputobjectat0x7f7faecdc9c0>,
'SERVER_PROTOCOL': 'HTTP/1.1',
'REQUEST_METHOD': 'GET',
'HTTP_ACCEPT_ENCODING': 'gzip,deflate',
'HTTP_CONNECTION': 'keep-alive',
'uwsgi.node': b'ubuntu',
'HTTP_DNT': '',
'UWSGI_ROUTER': 'http',
'SCRIPT_NAME': '',
'wsgi.multiprocess': False,
'QUERY_STRING': '',
'PATH_INFO': '/index.html',
'wsgi.url_scheme': 'http',
'HTTP_USER_AGENT': 'Mozilla/5.0(Macintosh;IntelMacOSX10_12_5)AppleWebKit/603.2.4(KHTML,likeGecko)Version/10.1.1Safari/603.2.4',
'SERVER_NAME': 'ubuntu'
}
4.Web动态服务器-多进程
# html文件夹网盘链接: https://pan.baidu.com/s/1wbZ92KLstff3GurLV_C0lg 密码: hp9o
# 下载完命令行解压后放到程序的同级路径下,解压命令: tar -zxvf 06_html.tar.gz -C ./
1.项目目录结构:
~/Desktop/Python/06_Web动态服务器 $ tree
.
├── html
│ ├── index.html
│ ├── ...
├── web
│ ├── __pycache__
│ │ └── mini_frame.cpython-37.pyc
│ └── mini_frame.py
└── web_server.py
2.web_server.py文件代码
import time
import socket
import sys
import re
import multiprocessing class WSGIServer(object):
"""定义一个WSGI服务器的类""" def __init__(self, port, documents_root): # 1. 创建套接字
self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 2.设置当服务器先close 即服务器端4次挥手之后资源能够立即释放,保证下次运行程序时可以立即绑定7890端口
self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# 3.绑定服务器地址
self.server_socket.bind(("", port))
# 4.变为监听套接字
self.server_socket.listen(128) # 设定资源文件的路径
self.documents_root = documents_root def set_app(self, app):
"""设定web框架可以调用的函数(对象)"""
self.app = app def run_forever(self):
"""循环运行服务器,等待客户端链接并为客户端服务""" # 等待对方链接
while True:
# 5.等待客户端链接
new_socket, new_addr = self.server_socket.accept()
# 6.创建一个新的进程来完成这个客户端的请求任务
new_socket.settimeout(3) # 设置套接字的超时检测3s
new_process = multiprocessing.Process(target=self.deal_with_request, args=(new_socket,))
new_process.start()
# 因为子进程已经复制了父进程的套接字等资源,所以父进程调用close不会将他们对应的这个链接关闭的
new_socket.close() def deal_with_request(self, client_socket):
"""用一个新的进程以长链接的方式,为这个浏览器服务""" while True:
try:
# 1.接收浏览器发送过来的HTTP请求
request = client_socket.recv(1024).decode("utf-8")
except Exception as ret:
print("========>", ret)
client_socket.close()
return # 判断浏览器是否关闭
if not request:
client_socket.close()
return request_lines = request.splitlines()
for i, line in enumerate(request_lines):
print(i, line) # 提取请求的文件(index.html)
# GET /a/b/c/d/e/index.html HTTP/1.1
ret = re.match(r"([^/]*)([^ ]+)", request_lines[0])
# 如果没有指定访问哪个页面,则默认访问index.html
# GET / HTTP/1.1
if ret:
print("正则提取数据:", ret.group(1))
print("正则提取数据:", ret.group(2))
file_name = ret.group(2)
if file_name == "/":
file_name = "/index.html" # 2.返回HTTP格式的数据给浏览器
# 2.1如果请求的资源不是以.py结尾,那么就是请求静态资源
if not file_name.endswith(".py"): # 读取文件数据
try:
f = open(self.documents_root + file_name, "rb")
except:
response_body = "file not found, Please enter the correct URL." response_header = "HTTP/1.1 404 not found\r\n"
response_header += "Content-Type: text/html; charset=utf-8\r\n"
response_header += "Content-Length: %d\r\n" % (len(response_body))
response_header += "\r\n" response = response_header + response_body # 没有对应的响应,返回404表示没有这个页面
client_socket.send(response.encode('utf-8')) else:
content = f.read()
f.close() response_body = content response_header = "HTTP/1.1 200 OK\r\n"
response_header += "Content-Length: %d\r\n" % (len(response_body))
response_header += "\r\n" # 将header返回给浏览器
client_socket.send(response_header.encode('utf-8') + response_body) # 2.2如果请求的资源是以.py结尾,那么就是请求动态资源
else:
# 准备一个字典,里面存放需要传递给web框架的数据
env = {}
# 存web返回的数据
response_body = self.app(env, self.set_response_headers) # 合并header和body
response_header = "HTTP/1.1 {status}\r\n".format(status=self.headers[0])
response_header += "Content-Type: text/html; charset=utf-8\r\n"
response_header += "Content-Length: %d\r\n" % len(response_body)
for temp_head in self.headers[1]:
response_header += "{0}:{1}\r\n".format(*temp_head) response = response_header + "\r\n"
response += response_body client_socket.send(response.encode('utf-8')) def set_response_headers(self, status, headers):
"""此方法会在web框架中被默认调用"""
# 添加服务器的一些信息
response_header_default = [
("Data", time.ctime()),
("Server", "ItCast-python mini web server")
] # 将web框架中传递回的状态码/响应头信息存储起来
# [字符串, [xxxxx, xxx2]]
self.headers = [status, response_header_default + headers] # 设置静态资源访问的路径
g_static_document_root = "./html"
# 设置动态资源访问的路径
g_dynamic_document_root = "./web" def main():
"""控制web服务器整体"""
# python3 web_server.py 7890 mini_frame:application
if len(sys.argv) == 3:
try:
# 获取web服务器的port
port = sys.argv[1]
if port.isdigit():
port = int(port)
# 获取web服务器需要动态资源时,访问的web框架名字
web_frame_module_app_name = sys.argv[2]
except Exception as ret:
print("端口输入错误...")
return
else:
print("运行方式如: python3 web_server.py 7890 mini_frame:application")
return print("http服务器使用的port:%s" % port) # 将动态路径即存放py文件的路径,添加到path中,python解释器才可以找到路径
sys.path.append(g_dynamic_document_root) ret = re.match(r"([^:]*):(.*)", web_frame_module_app_name)
if ret:
# 获取模块名
web_frame_module_name = ret.group(1)
# 获取可以调用web框架的应用名称
app_name = ret.group(2) # 导入web框架的主模块,返回值标记这个导入的模块
web_frame_module = __import__(web_frame_module_name)
# 获取那个可以直接调用的函数(对象)
app = getattr(web_frame_module, app_name) # print(app) # for test # 启动http服务器
http_server = WSGIServer(port, g_static_document_root)
# 将方法封装成类的属性
http_server.set_app(app)
# 运行http服务器
http_server.run_forever() if __name__ == "__main__":
main()
3.mini_frame.py文件代码
import time def application(environ, start_response):
"""遵循WSGI标准的HTTP处理函数 :param environ: 一个包含所有HTTP请求信息的dict对象
:param start_response: 一个发送HTTP响应的函数
:return: 返回body信息
"""
status = "200 OK"
response_headers = [("Content-Type", "text/html")]
start_response(status, response_headers)
return str(environ) + "==Hello world from a simple WSGI application!--->%s\n" % time.ctime()
4.完整项目网盘链接: https://pan.baidu.com/s/1CpO1502f59gEgwCsXaYXlA 密码: flnq
5.mini-web框架
1.项目目录结构:
~/Desktop/python3/07_mini-web框架 $ tree -L 2
.
├── __init__.py
├── dynamic # 存放py模块
│ ├── __init__.py
│ ├── __pycache__
│ └── mini_frame.py # mini框架
├── log.txt # 日志
├── readme.txt # 说明文档
├── run.sh # shell运行脚本
├── static
│ ├── css
│ └── js
├── stock_db.sql # 数据库数据准备生成脚本
├── templates # 存放模板文件
│ ├── center.html # 个人信息界面
│ ├── index.html # 股票信息界面
│ └── update.html # 修改备注页面
├── web_server.conf # mini web服务器配置文件
└── web_server.py # mini web服务器
2.数据库准备
-- 创建数据库
create database stock_db charset=utf8;
-- 选中数据库
use stock_db;
-- 导入数据,sql文件在完整项目网盘链接解压文件中
source stock_db.sql
3.web_server.py文件代码
import time
import socket
import sys
import re
import multiprocessing class WSGIServer(object):
"""定义一个WSGI服务器的类""" def __init__(self, port, documents_root): # 1. 创建套接字
self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 2.设置当服务器先close 即服务器端4次挥手之后资源能够立即释放,保证下次运行程序时可以立即绑定7890端口
self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# 3.绑定服务器地址
self.server_socket.bind(("", port))
# 4.变为监听套接字
self.server_socket.listen(128) # 设定资源文件的路径
self.documents_root = documents_root def set_app(self, app):
"""设定web框架可以调用的函数(对象)"""
self.app = app def run_forever(self):
"""循环运行服务器,等待客户端链接并为客户端服务""" # 等待对方链接
while True:
# 5.等待客户端链接
new_socket, new_addr = self.server_socket.accept()
# 6.创建一个新的进程来完成这个客户端的请求任务
new_socket.settimeout(3) # 设置套接字的超时监测3s
new_process = multiprocessing.Process(target=self.deal_with_request, args=(new_socket,))
new_process.start()
# 因为子进程已经复制了父进程的套接字等资源,所以父进程调用close不会将他们对应的这个链接关闭的
new_socket.close() def deal_with_request(self, client_socket):
"""用一个新的进程以长链接的方式,为这个浏览器服务""" while True:
try:
# 1.接收浏览器发送过来的HTTP请求
request = client_socket.recv(1024).decode("utf-8")
except Exception as ret:
print("========>", ret)
client_socket.close()
return # 判断浏览器是否关闭
if not request:
client_socket.close()
return request_lines = request.splitlines()
for i, line in enumerate(request_lines):
print(i, line) # 提取请求的文件(index.html)
# GET /a/b/c/d/e/index.html HTTP/1.1
ret = re.match(r"([^/]*)([^ ]+)", request_lines[0])
# 如果没有指定访问哪个页面,则默认访问index.html
# GET / HTTP/1.1
if ret:
print("正则提取数据:", ret.group(1))
print("正则提取数据:", ret.group(2))
file_name = ret.group(2)
if file_name == "/":
file_name = "/index.html" # 2.返回HTTP格式的数据给浏览器
# 2.1如果请求的资源不是以.html结尾,那么就是请求静态资源
if not file_name.endswith(".html"): # 读取文件数据
try:
print(self.documents_root + file_name)
f = open(self.documents_root + file_name, "rb")
except:
response_body = "file not found, 请输入正确的URL..." response_header = "HTTP/1.1 404 not found\r\n"
response_header += "Content-Type: text/html; charset=utf-8\r\n"
response_header += "Content-Length: %d\r\n" % (len(response_body.encode("utf-8")))
response_header += "\r\n" response = response_header + response_body # 没有对应的响应,返回404表示没有这个页面
client_socket.send(response.encode("utf-8")) else:
content = f.read()
f.close() response_body = content response_header = "HTTP/1.1 200 OK\r\n"
response_header += "Content-Length: %d\r\n" % (len(response_body))
response_header += "\r\n" # 将静态请求返回给浏览器
client_socket.send(response_header.encode('utf-8') + response_body) # 2.2如果请求的资源是以.html结尾,那么就是请求动态资源
else:
# 准备一个字典,里面存放需要传递给web框架的数据
env = dict()
env["PATH_INFO"] = file_name # 例如 index.py
# 存web返回的数据
response_body = self.app(env, self.set_response_headers) # 合并header和body
response_header = "HTTP/1.1 {status}\r\n".format(status=self.headers[0])
response_header += "Content-Type: text/html; charset=utf-8\r\n"
response_header += "Content-Length: %d\r\n" % len(response_body.encode("utf-8"))
for temp_head in self.headers[1]:
response_header += "{0}:{1}\r\n".format(*temp_head) response = response_header + "\r\n"
response += response_body client_socket.send(response.encode('utf-8')) def set_response_headers(self, status, headers):
"""此方法会在web框架中被默认调用"""
# 添加服务器的一些信息
response_header_default = [
("Data", time.ctime()),
("Server", "ItCast-python mini web server")
] # 将web框架中传递回的状态码/响应头信息存储起来
# [字符串, [xxxxx, xxx2]]
self.headers = [status, response_header_default + headers] # 设置静态资源访问的路径
# g_static_document_root = "./html"
# # 设置动态资源访问的路径
# g_dynamic_document_root = "./web" def main():
"""控制web服务器整体"""
# python3 web_server.py 7890 mini_frame:application
if len(sys.argv) == 3:
try:
# 获取web服务器的port
port = sys.argv[1]
if port.isdigit():
port = int(port)
# 获取web服务器需要动态资源时,访问的web框架名字
web_frame_module_app_name = sys.argv[2]
except Exception as ret:
print("端口输入错误...")
return
else:
print("运行方式如: python3 web_server.py 7890 mini_frame:application")
return # 读取配置文件信息
with open("./web_server.conf") as f:
conf_info = eval(f.read())
# conf_info字典里的数据为
# {
# "static_path": "./static",
# "dynamic_path": "./dynamic"
# } print("http服务器使用的port:%s" % port) # 将动态路径即存放py文件的路径,添加到path中,python解释器才可以找到路径
sys.path.append(conf_info["dynamic_path"]) ret = re.match(r"([^:]*):(.*)", web_frame_module_app_name)
if ret:
# 获取模块名
web_frame_module_name = ret.group(1)
# 获取可以调用web框架的应用名称
app_name = ret.group(2) # 导入web框架的主模块,返回值标记这个导入的模块
web_frame_module = __import__(web_frame_module_name)
# 获取那个可以直接调用的函数(对象)
app = getattr(web_frame_module, app_name) # print(app) # for test # 启动http服务器
http_server = WSGIServer(port, conf_info["static_path"])
# 将方法封装成类的属性
http_server.set_app(app)
# 运行http服务器
http_server.run_forever() if __name__ == "__main__":
main()
4.mini_frame.py文件代码
# import time
# import os
import re
from urllib.parse import unquote
import logging import pymysql template_root = "./templates" # 用来存放url路由映射
# url_route = {
# "/index.html": index_func,
# "/center.html": center_func
# }
g_url_route = dict() def route(url):
def set_func(func):
# 添加键值对,key是需要访问的url,value是当这个url需要访问的时候,需要调用的函数引用
g_url_route[url] = func def call_func(*args, **kwargs):
return func(*args, **kwargs) return call_func return set_func @route(r"/index.html")
def index(ret):
"""返回index.py需要的页面内容"""
# return "hahha" + os.getcwd() # for test 路径问题
try:
f = open(template_root + "/index.html")
except Exception as ret:
return "打开股票信息页面产生了异常: %s" % ret
else:
content = f.read()
f.close() # --------通过数据库更新股票信息数据-------
# 创建connection连接
db = pymysql.connect(host="localhost", port=3306, user="root", password="", database="stock_db",
charset="utf8")
# 获取cursor对象
cursor = db.cursor()
sql = """select * from info;"""
cursor.execute(sql)
data_from_mysql = cursor.fetchall()
cursor.close()
db.close() html_template = """
<tr>
<td>%d</td>
<td>%s</td>
<td>%s</td>
<td>%s</td>
<td>%s</td>
<td>%s</td>
<td>%s</td>
<td>%s</td>
<td>
<input type="button" value="添加" id="toAdd" name="toAdd" systemidvaule="%s">
</td>
</tr>""" html = "" for info in data_from_mysql:
html += html_template % (info[0], info[1], info[2], info[3], info[4], info[5], info[6], info[7], info[1]) content = re.sub(r"\{%content%\}", html, content) return content @route(r"/center.html")
def center(ret):
"""返回center.html需要的页面内容"""
# return "hahha" + os.getcwd() # for test 路径问题
try:
f = open(template_root + "/center.html")
except Exception as ret:
return "打开个人中心页面产生了异常: %s" % ret
else:
content = f.read()
f.close() # --------通过数据库更新个人中心数据-------
# 创建connection连接
db = pymysql.connect(host="localhost", port=3306, user="root", password="", database="stock_db",
charset="utf8")
# 获取cursor对象
cursor = db.cursor()
sql = """select
i.code,i.short,i.chg,i.turnover,i.price,i.highs,j.note_info from info as i
inner join focus as j on i.id=j.info_id;"""
cursor.execute(sql)
data_from_mysql = cursor.fetchall()
cursor.close()
db.close() html_template = """
<tr>
<td>%s</td>
<td>%s</td>
<td>%s</td>
<td>%s</td>
<td>%s</td>
<td>%s</td>
<td>%s</td>
<td>
<a type="button" class="btn btn-default btn-xs" href="/update/%s.html"> <span class="glyphicon glyphicon-star" aria-hidden="true"></span> 修改 </a>
</td>
<td>
<input type="button" value="删除" id="toDel" name="toDel" systemidvaule="%s">
</td>
</tr>
""" html = "" for info in data_from_mysql:
html += html_template % (info[0], info[1], info[2], info[3], info[4], info[5], info[6], info[0], info[0]) content = re.sub(r"\{%content%\}", html, content) return content # 给路由添加正则表达式的原因: 在实际开发时,url中往往会带有很多参数,例如/add/000007.html中000007就是参数
# 如果没有正则的话,那么就需要编写N次@route来进行添加url对应的函数到字典中,此时字典中的键值对有N个,浪费空间
# 而采用了正则的话,那么只要编写1次@route就可以完成多个url例如/add/00007.html /add/000036.html等对应同一个函数
@route(r"/add/(\d+)\.html")
def add_focus(ret):
"""添加对应股票的关注"""
# 1.获取股票代码
stock_code = ret.group(1) # 2.判断试下是否有这个股票代码
# 创建connection连接
db = pymysql.connect(host="localhost", port=3306, user="root", password="", database="stock_db",
charset="utf8")
cursor = db.cursor()
sql = """select * from info where code=%s;"""
cursor.execute(sql, (stock_code,))
# 如果要是没有这个股票代码,那么就认为是非法的请求
if not cursor.fetchone():
cursor.close()
db.close()
return "没有这支股票,大哥,我们是创业公司,请手下留情..." # 3.判断以下是否已经关注过
sql = """ select * from info as i inner join focus as f on i.id=f.info_id where i.code=%s;"""
cursor.execute(sql, (stock_code,))
# 如果查出来了,那么表示已经关注过
if cursor.fetchone():
cursor.close()
cursor.close()
return "已经关注过了,请勿重复关注..." # 4.添加关注
sql = """insert into focus (info_id) select id from info where code=%s;"""
cursor.execute(sql, (stock_code,))
db.commit()
cursor.close()
db.close() return "关注成功...." @route(r"/del/(\d+)\.html")
def del_focus(ret):
"""取消对应股票的关注"""
# 1.获取股票代码
stock_code = ret.group(1) # 2.判断试下是否有这个股票代码
db = pymysql.connect(host="localhost", port=3306, user="root", password="", database="stock_db",
charset="utf8")
cursor = db.cursor()
sql = """select * from info where code=%s;"""
cursor.execute(sql, (stock_code,))
# 如果要是没有这个股票代码,那么就认为是非法的请求
if not cursor.fetchone():
cursor.close()
db.close()
return "没有这支股票,大哥,我们是创业公司,请手下留情..." # 3. 判断以下是否已经关注过
sql = """ select * from info as i inner join focus as f on i.id=f.info_id where i.code=%s;"""
cursor.execute(sql, (stock_code,))
# 如果没有关注过,那么表示非法的请求
if not cursor.fetchone():
cursor.close()
db.close()
return "%s之前未关注,请勿取消关注..." % stock_code # 4.取消关注
# sql = """insert into focus (info_id) select id from info where code=%s;"""
sql = """delete from focus where info_id = (select id from info where code=%s);"""
cursor.execute(sql, (stock_code,))
db.commit()
cursor.close()
db.close() return "取消关注成功...." @route(r"/update/(\d*)\.html")
def update(ret):
"""显示更新页面的内容"""
# 1.获取股票代码
stock_code = ret.group(1) # 2.打开模版
try:
template_file_name = template_root + "/update.html"
f = open(template_file_name)
except Exception as ret:
return "%s...没有找到%s" % (ret, template_file_name)
else:
content = f.read()
f.close() # 3. 根据股票代码查询相关的备注信息
db = pymysql.connect(host="localhost", port=3306, user="root", password="", database="stock_db",
charset="utf8")
cursor = db.cursor()
sql = """select f.note_info from focus as f inner join info as i on i.id=f.info_id where i.code=%s;"""
cursor.execute(sql, (stock_code,))
stock_note_info = cursor.fetchone()
cursor.close()
db.close() content = re.sub(r"\{%code%\}", stock_code, content)
content = re.sub(r"\{%note_info%\}", str(stock_note_info[0]), content) return content @route(r"/update/(\d*)/(.*)\.html")
def update_note_info(ret):
"""进行数据的真正更新""" stock_code = ret.group(1)
stock_note_info = ret.group(2)
stock_note_info = unquote(stock_note_info) # 在向数据库存储时进行url解码 # 创建connection连接
db = pymysql.connect(host="localhost", port=3306, user="root", password="", database="stock_db",
charset="utf8")
# 获取cursor对象
cursor = db.cursor()
sql = """update focus set note_info=%s where info_id = (select id from info where code=%s);"""
cursor.execute(sql, (stock_note_info, stock_code))
db.commit()
cursor.close()
db.close() return "修改成功" def application(environ, start_response):
"""遵循WSGI标准的HTTP处理函数 :param environ: 一个包含所有HTTP请求信息的dict对象
:param start_response: 一个发送HTTP响应的函数
:return: 返回body信息
"""
status = '200 OK'
response_headers = [('Content-Type', 'text/html')]
start_response(status, response_headers) file_name = environ['PATH_INFO']
# 添加log日志功能
logging.basicConfig(level=logging.INFO,
filename='./log.txt',
filemode='a',
format='%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s') logging.info("访问的是: %s" % file_name) try:
# return g_url_route[file_name](file_name) # 路由功能
for url, call_func in g_url_route.items():
print(url)
ret = re.match(url, file_name)
if ret:
return call_func(ret)
else:
logging.warning("没有对应的函数....")
return "请求的url(%s)没有对应的函数...." % file_name except Exception as ret:
return "mini_frame框架产生了异常: %s" % ret
5.完整项目网盘链接: https://pan.baidu.com/s/1i7qdYFl0N10_AUrjJPK3Ow 密码: o1qc
6.未实现的功能
1.把操作数据库的部分单独封装到一个函数中,使用时直接调用
2.配置MySQL主从服务器-从服务器查询操作,主服务器增删改操作
3.用元类实现ORM-即操作数据库部分用元类实现
6.标准库模块实现Web动态服务器
try:
# Python2中的导入
from BaseHTTPServer import BaseHTTPRequestHandler
from BaseHTTPServer import HTTPServer
except ImportError:
# Python3中的导入
from http.server import BaseHTTPRequestHandler
from http.server import HTTPServer class RequestHander(BaseHTTPRequestHandler):
"""请求处理类""" def do_GET(self):
"""固定的处理GET请求方法"""
# 查看请求头
print(self.headers)
print("Do method get")
# 组织响应行
self.send_response(200)
# 组织响应头
self.send_header("Content-Type", "text/html")
self.send_header("charset", "utf-8")
# 响应头结束
self.end_headers()
# 发送响应体
self.wfile.write(b"<h1>Hello World!</h1>")
return def do_POST(self):
"""固定的处理POST请求方法"""
pass def main():
# 指定地址
address = ("0.0.0.0", 7890)
# 生成服务器对象
server = HTTPServer(address, RequestHander)
# 运行
server.serve_forever() if __name__ == "__main__":
main()
15_Web框架-mini frame的更多相关文章
- thinkphp 加载静态框架frameset frame 浏览器显示空白
我觉得静态框架这个东西非常奇怪,可能是因为没有研究透它. 我的情况是这样的,我之前做过的一个面向对象没有基于thinkPHP,的项目中用同一套后台静态框架没有问题,但用thinkphp后台的index ...
- 框架frame
使用框架切分网页 效果: 代码: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"& ...
- Window 对象 HTML框架标签(Frame)
Window 对象 Window 对象表示浏览器中打开的窗口. 如果文档包含框架(frame 或 iframe 标签),浏览器会为 HTML 文档创建一个 window 对象,并为每个框架创建一个额外 ...
- RobotFramework:切换页面和Frame框架
切换页面主要有以下两种情况 在浏览器上打开多个窗口(Windows),在窗口内切换 打开多个浏览器(Browser),在多个浏览器内切换 1. 切换窗口 该操作适用于:打开两(多)个窗口页面,在打开的 ...
- Frameset框架
总结一下.通过使用Frameset框架,可以在同一个浏览器窗口中显示不止一个页面. 先举个例子: <frameset rows="> <frame src="to ...
- Frameset框架优缺点--来自新浪微博
原文地址:http://blog.sina.com.cn/s/blog_4a4b1b010100p6ro.html HTML框架简述 一个浏览器窗体可以通过几个页面的组合来显示.我们可以使用框架来 ...
- javascript中的窗口和框架
框架: 在网络上我们可以看到很多WEB应用程序都是使用框架(frame)来分隔浏览器窗口的,就想一块块玻璃隔板把窗口分隔成好几个小窗口,并且可以在不同的小窗口中加载显示不同的页面,这样在我们看来好像是 ...
- html框架
1.框架的概念 框架:将一个浏览器窗口划分成若干个小窗口 2.框架集合框架页 框架集<frameset>:主要用来划分窗口的. 框架页<frame>:主要用来指定窗口默认显示的 ...
- HTML笔记(四) 框架
通过框架,可以在一个窗口显示多个页面.而所谓的框架,就是指每一份HTML文档. 框架结构标签<frameset> 定义如何将窗口分割为框架. frameset定义了一系列的行列. rows ...
随机推荐
- Android Studio局部管理器
1.LinearLayout(线性布局) 该布局将其中的View子控件按照水平或者垂直方向排列.但是需要注意不管是水平还是竖直,对应的每一行或列都只能放一个控件. 线性布局两种排法: 从左到右:and ...
- java循环嵌套与跳转语句(break,continue)
一 循环嵌套 嵌套循环是指在一个循环语句的循环体中再定义一个循环语句的语法结构.while.do…while. for循环语句都可以进行嵌套,并且它们之间也可以互相嵌套,如最常见的在for循环中嵌套f ...
- 记录使用Python登录浙江大学统一身份认证
背景 现在每天要进行健康情况上报,但是因为经常睡过头忘记打卡,于是想着写一个程序来自动打卡. 统一身份认证 访问健康情况上报页面(https://healthreport.zju.edu.cn/nco ...
- 【算法•日更•第五十期】二分图(km算法)
▎前言 戳开这个链接看看,惊不惊喜,意不意外?传送门. 没想到我的博客竟然被别人据为己有了,还没办法投诉. 这年头写个博客太难了~~~ 之前小编写过了二分图的一些基础知识和匈牙利算法,今天来讲一讲km ...
- js使用html2canvas 生成图片然后下载
1:html2canvas官网 首先去官网把这个JS下载下来 <!DOCTYPE html> <html lang="en"> <head> & ...
- 使用 codeblocks 编写C++ udp组播程序遇到的问题
编译错误 会出现好多undefined reference to'WSAStartup to@8之类的错误,都是undefind开头的 解决方法: Settings -> Compiler se ...
- 基于官方Drone-CI 的alpine版本asia亚洲时区构建支持. Drone-CI based alpine Timezone Build
基于官方Drone-CI 的alpine版本最简化添加亚洲时区Dockerfile构建支持. iotd@Github: drone-ci-based-alpine-timezone-build 如添加 ...
- 进阶6:连接查询 一、sql92标准
#进阶6:连接查询/*含义:又称多表查询,当查询的字段来自于多个表时,就会用到连接查询 笛卡尔乘积现象:表1 有m行,表2有n行,结果=m*n行 发生原因:没有有效的连接条件如何避免:添加有效的连接条 ...
- 超详细的阿里字节Spring面试技术点总结(建议收藏)
前言 Spring作为现在最流行Java开发技术,其内部源码设计非常优秀. Spring这个词对于Java开发者想必不会陌生,可能你每天都在使用Spring,享受着Spring生态提供的服务.现在很多 ...
- MariaDB二进制安装
下载二进制的MariaDB https://downloads.mariadb.org/mariadb/10.2.16/ 安装过程 下载&解压 下载到/tools安装到/application ...