web服务器进阶
- 2019 年 10 月 6 日
- 笔记
1、实现自己指定端口运行我们的web服务器
如果我们的web服务器端口被占用,那么我们的web服务器直接挂掉。
怎么实现?我们可以在执行的时候指定一个端口。
复习:
创建一个Demo.py
写上:
import sys
print(sys.argv)
我们在黑窗口运行一个python文件的时候,执行命令:
python Demo 123 456
会输出:['Demo.py', '123', '456']
可见,我们是可以给一个程序传递参数的。我们用这个功能,来给我们的web服务器指定端口和框架。
2、利用1中的例子,再给一个框架名,让他直接传一个框架进入。
我们希望运行 python web服务器 7891 Demo:application
来实现调用Demo框架的application方法。
3、写一个配置文件,将web服务器中的寻找文件的路径写进去。
解决上面三个问题才是真的解耦。
思路已经提供给大家,并且看基础是能够写出来的。
接下来我们利用装饰器完成路由功能。对装饰器不懂的可以看看这篇文章:python基础三
什么是路由功能?
就是请求的url,我们上次通过if判断来写的,很恶心,用另一种方法些
我们将Demo框架写成这样(不用再修改web服务器了):
URL_FUNC_DICT = dict()
def url_func(url):
def set_fun(func):
URL_FUNC_DICT[url] = func
def call_func(*args,**kwargs):
return func(*args,**kwargs)
return call_func
return set_fun
@url_func('/login.py')
def login():
# 这里也可以读取文件
return '<h1>登录的页面</h1>'
@url_func('/create.py')
def create():
return '<h1>注册的页面</h1>'
def application(evairon,start_response):
# 第一个参数返回状态码,第二个以键值的方式返回你想添加的head部分
start_response('200 ok',[('Content-Type','text/html;charset=utf-8')])
# 返回给网页的内容
try:
file_name = evairon['path_info']
fun = URL_FUNC_DICT[file_name]
return fun()
except Exception as e:
return '未找到文件'
伪静态实现
在前面说过我们只是暂时任务请求以.py结尾的url为动态的。实际上不是这样。
上面才是动态网页?
静态的:域名/index.html
动态的:域名/index.aspx?page=xxx&xxxxx=xxxx,
伪静态:域名/cour/index.html
web服务器实现伪静态:
修改web服务器中判断是.py结尾为以.html结尾,其它不用管。
修改Demo框架中装饰器的参数为.html结尾。
给Demo框架连接数据库并显示到页面
数据库运用我们mysql教程中给大家演示的那个student数据库。
对于python操作数据库没了解的请去看mysql数据库系列文章。
mysql简单基础,我们在Demo新创建一个mysqldata方法,并且加上装饰器
@url_func('/mysqldata.html')
def mysqldata():
conn = connect(host='localhost',port=3306,user='root',password='123456',database='student',charset='utf8')
cursor = conn.cursor()
cursor.execute("select * from studentinfo")
text = cursor.fetchall()
cursor.close()
conn.close()
return str(text)
在浏览器中输入127.0.0.1:端口号/mysqldata.html即可看到内容。
查出来是这样的:((1, '张三', 1, '男', 23, '武汉', b'x00'), (2, '小花', 2, '女', 20, '长沙', b'x00'), (3, '李四', 3, '男', 21, '上海', b'x00'), (4, '小猫', 1, '女', 18, '北京', b'x00'), (6, '小狗', 3, '女', 25, '成都', b'x00'), (7, '赵六', 1, '男', 26, '天津', b'x00'))
看着很恶心,给个格式。修改mysqldata方法:
这里会用到html的知识点,希望自己补充。修改成:
@url_func('/mysqldata.html')
def mysqldata():
conn = connect(host='localhost',port=3306,user='root',password='123456',database='student',charset='utf8')
cursor = conn.cursor()
cursor.execute("select * from studentinfo")
text = cursor.fetchall()
cursor.close()
conn.close()
html = "<table border='1' width = '400px' cellspacing='0' cellpadding='0'>"
tr_html = '''
<tr>
<td>%s</td>
<td>%s</td>
<td>%s</td>
<td>%s</td>
<td>%s</td>
<td>%s</td>
<td>%s</td>
</tr>
'''
for item in text:
html += tr_html %(item[0],item[1],item[2],item[3],item[4],item[5],item[6])
html +="</table>"
return str(html)
这样就好看多了。当然你想显示什么就数据库查什么就好了。
完善Demo框架
1、给路由添加正则
现在我们的url返回的都是固定的,比如我们想要删除一个数据,请求的url为/delete/xxx.html
我们需要传递一个xxx,表示id,这个id是不确定的,所以我们需要正则匹配,只要是这种格式,我们都执行
delete方法。修改如下:
修改application方法:
def application(evairon,start_response):
# 第一个参数返回状态码,第二个以键值的方式返回你想添加的head部分
start_response('200 ok',[('Content-Type','text/html;charset=utf-8')])
# 返回给网页的内容
try:
file_name = evairon['path_info']
for url,func in URL_FUNC_DICT.items():
# 匹配是否有这个函数,有返回回去
ret = re.match(url,file_name)
if ret:
return func(ret)
except Exception as e:
return '未找到文件 %s'%e
添加delete方法,并匹配所有url为/delete/xxx.html格式的都执行该方法。
@url_func(r'/delete/(d+).html')
def delete(ret):
return '删除方法。ok'
由于给所有函数传递了一个url,所以需要给上面的函数都添加一个参数。
执行:成功返回删除方法。ok,那我们继续完善删除方法。
@url_func(r'/delete/(d+).html')
def delete(ret):
# 获取id值
id = ret.group(1)
# 执行sql删除
conn = connect(host='localhost',port=3306,user='root',password='123456',database='student',charset='utf8')
cursor = conn.cursor()
count = cursor.execute("delete from studentinfo where studentid = %s",(id,))
if count:
conn.commit()
cursor.close()
conn.close()
return '删除成功。ok!!'
else:
return '删除失败!'
其他修改啊,添加,只是sql语句不同,都大同小异。
不过在修改的时候要修改正则,传给数据的还要有修改值没有了解post请求就换个正则匹配
比如127.0.0.1/修改方法/要修改的id/要修改的内容.html,用正则匹配出id和要修改的内容就可以了。
但是有个问题,当我们传递的内容或者汉子的时候会出现乱码,因为是通过url传递的,中途会有个url编码的过程,
我们需要解码:
1、需要导入模块
import urllib
解码:urllib.parse.unquote()
编码:urllib.parse.quote()
添加日志模块
不会日志模块需要看基础:python常用模块二
导入日志模块:import logging
修改application方法:
def application(evairon,start_response):
# 第一个参数返回状态码,第二个以键值的方式返回你想添加的head部分
start_response('200 ok',[('Content-Type','text/html;charset=utf-8')])
file_name = evairon['path_info']
# 写入日志
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:
for url,func in URL_FUNC_DICT.items():
# 匹配是否有这个函数,有返回回去
ret = re.match(url,file_name)
if ret:
return func(ret)
except Exception as e:
logging.WARNING('找不到文件')
return '未找到文件 %s'%e