怎么⽤python做⼀个⽹页框架_⽤Python写⼀个简单的Web框
架
⼀、概述
在Python中,WSGI(Web Server Gateway Interface)定义了Web服务器与Web应⽤(或Web框架)之间的标准接⼝。在WSGI的规范下,各种各样的Web服务器和Web框架都可以很好的交互。
由于WSGI的存在,⽤Python写⼀个简单的Web框架也变得⾮常容易。然⽽,同很多其他的强⼤软件⼀样,要实现⼀个功能丰富、健壮⾼效的Web框架并⾮易事;如果您打算这么做,可能使⽤⼀个现成的Web框架(如 Django、Tornado、web.py 等)会是更合适的选择。
本⽂尝试写⼀个类似web.py的Web框架。好吧,我承认我夸⼤其辞了:⾸先,web.py并不简单;其次,本⽂只重点实现了 URL调度(URL dispatch)部分。
⼆、从demo_app开始
⾸先,作为⼀个初步体验,我们可以借助 wsgiref.simple_server 来搭建⼀个简单⽆⽐(trivial)的Web应⽤:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from wsgiref.simple_server import make_server, demo_app
httpd = make_server('', 8086, demo_app)
sa = sockname()
print '{0}:{1}/'.format(*sa)
# Respond to requests until process is killed
httpd.serve_forever()
运⾏脚本:
$ python code.py
三、WSGI中的application
WSGI中规定:application是⼀个 可调⽤对象(callable object),它接受 environ 和 start_response 两个参数,并返回⼀个 字符串迭代对象。
其中,可调⽤对象 包括 函数、⽅法、类 或者 具有__call__⽅法的 实例;environ 是⼀个字典对象,包括CGI风格的环境变量(CGI-style environment variables)和 WSGI必需的变量(WSGI-required variables);start_response 是⼀个可调⽤对象,它接受两个 常规参数(status,response_headers)和 ⼀个 默认参数(exc_info);字符串迭代对象 可以是 字符串列表、⽣成器函数 或者 具有__iter__⽅法的可迭代实例。更多细节参考 Specification Details。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""application.py"""
def simple_app(environ, start_response):
"""Simplest possible application object"""
status = '200 OK'
response_headers = [('Content-type', 'text/plain')]
start_response(status, response_headers)
return ['Hello world!\n']
现在⽤simple_app来替换demo_app:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""code.py"""
from wsgiref.simple_server import make_server
from application import simple_app as app
if __name__ == '__main__':
httpd = make_server('', 8086, app)
sa = sockname()
print '{0}:{1}/'.format(*sa)
# Respond to requests until process is killed
httpd.serve_forever()
四、区分URL
倒腾了⼀阵⼦后,您会发现不管如何改变URL中的path部分,得到的响应都是⼀样的。因为simple_app只识别host+port部分。为了对URL中的path部分进⾏区分处理,需要修改application.py的实现。
⾸先,改⽤ 类 来实现application:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""application.py"""
class my_app:
def __init__(self, environ, start_response):
self.start = start_response
def __iter__(self):
status = '200 OK'
response_headers = [('Content-type', 'text/plain')]
self.start(status, response_headers)
yield "Hello world!\n"
然后,增加对URL中path部分的区分处理:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""application.py"""
class my_app:
def __init__(self, environ, start_response):
self.start = start_response
def __iter__(self):
path = viron['PATH_INFO']
if path == "/":
return self.GET_index()
elif path == "/hello":
return self.GET_hello()
else:
found()
def GET_index(self):
status = '200 OK'
response_headers = [('Content-type', 'text/plain')]
self.start(status, response_headers)
yield "Welcome!\n"
def GET_hello(self):
status = '200 OK'
response_headers = [('Content-type', 'text/plain')]
self.start(status, response_headers)
yield "Hello world!\n"
def notfound(self):
status = '404 Not Found'
response_headers = [('Content-type', 'text/plain')]
self.start(status, response_headers)
yield "Not Found\n"
修改code.py中的from application import simple_app as app,⽤my_app来替换simple_app后即可体验效果。
五、重构
上⾯的代码虽然奏效,但是在编码风格和灵活性⽅⾯有很多问题,下⾯逐步对其进⾏重构。
1、正则匹配URL
消除URL硬编码,增加URL调度的灵活性:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""application.py"""
import re >>修改点
class my_app:
urls = (
("/", "index"),
("/hello/(.*)", "hello"),
) >>修改点
def __init__(self, environ, start_response):
self.start = start_response
def __iter__(self): >>修改点
path = viron['PATH_INFO']
method = viron['REQUEST_METHOD']
for pattern, name in self.urls:
m = re.match('^' + pattern + '$', path)
if m:
# pass the matched groups as arguments to the function args = m.groups()
funcname = method.upper() + '_' + name
if hasattr(self, funcname):
func = getattr(self, funcname)
return func(*args)
found()
def GET_index(self):
status = '200 OK'
response_headers = [('Content-type', 'text/plain')]
self.start(status, response_headers)
yield "Welcome!\n"
def GET_hello(self, name): >>修改点
status = '200 OK'
response_headers = [('Content-type', 'text/plain')]
self.start(status, response_headers)
yield "Hello %s!\n" % name
def notfound(self):
status = '404 Not Found'
response_headers = [('Content-type', 'text/plain')]
self.start(status, response_headers)
yield "Not Found\n"
2、DRY
消除GET_*⽅法中的重复代码,并且允许它们返回字符串:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""application.py"""
import re
如何做网页class my_app:
urls = (
("/", "index"),
("/hello/(.*)", "hello"),
)
def __init__(self, environ, start_response): >>修改点viron = environ
self.start = start_response
self.status = '200 OK'
self._headers = []
def __iter__(self): >>修改点
result = self.delegate()
self.start(self.status, self._headers)
# 将返回值result(字符串 或者 字符串列表)转换为迭代对象
if isinstance(result, basestring):
return iter([result])
else:
return iter(result)
def delegate(self): >>修改点
path = viron['PATH_INFO']
method = viron['REQUEST_METHOD']
for pattern, name in self.urls:
m = re.match('^' + pattern + '$', path)
if m:
# pass the matched groups as arguments to the function
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
基于VBA实现的2种爬取网页的方法-细节解释
下一篇 »
热门文章
-
建党100周年是哪一年?
2025-02-08 -
建军节回顾中国军队的伟大成就
2025-02-08 -
建军节纪念中国人民解放军成立的日子
2025-02-08 -
重温建军历程建军节回顾中国军队的奋斗历史
2025-02-08 -
建军节庆祝中国军队的辉煌成就
2025-02-08 -
建军节专题回顾中国军队的历史辉煌与伟大成就
2025-02-08 -
建军节回顾中国军队的辉煌历史
2025-02-08 -
纪念建军节见证中国国防事业的伟大成就与发展
2025-02-08 -
纪念建军节回顾中国军队的辉煌历史与发展成就
2025-02-08 -
八一建军节的历史背景
2025-02-08 -
为热烈庆祝建军96周年
2025-02-08 -
建军节相关知识和历史故事
2025-02-08 -
2019年11月1日是建军多少周年
2025-02-08 -
八一建军节的来历和由来
2025-02-08 -
三年级数学下拓展题
2025-02-08 -
...建设世界一流军队——热烈庆祝中国人民解放军建军90 周年
2025-02-08 -
2021年是中国人民解放军建军多少周年
2025-02-08 -
考研政治-建军90周意味着哪些政治考点
2025-02-08 -
介绍建军96周年伟大成就和历史功勋
2025-02-08 -
幼儿园大班基本知识100个常识
2025-02-08
最新文章
-
关于对志愿军的描写和赞扬的作文100字
2025-02-08 -
胡绳《中国共产党的七十年》配套模拟试题及详解【圣才出品】_百度文 ...
2025-02-08 -
传媒从业者必备:2014年新闻月历
2025-02-08 -
2023年全民国防教育知识网络竞赛考试模拟卷
2025-02-08 -
人教版数学三年级上册 7单元(年月日)练习题
2025-02-08 -
关于建军节的事迹简短100字
2025-02-08
发表评论