python 实现web框架simfish

简介:

本文主要记录本人利用python实现web框架simfish的过程。源码github地址:simfish

WSGI HTTP Server

wsgi模块提供了简单的simple_server,

wsgiref.simple_server.make_server(host, port, app, server_class=WSGIServer, handler_class=WSGIRequestHandler)

官方提供的例子,

复制代码
from wsgiref.simple_server import make_server, demo_app

httpd = make_server('', 8000, demo_app)
print "Serving HTTP on port 8000..."

# Respond to requests until process is killed
httpd.serve_forever()

# Alternative: serve one request, then exit
httpd.handle_request()
复制代码

访问http://127.0.0.1:8000来检查是否正常运行。

因此,有了wsgi的帮助,我们只需要实现我们自己的demo_app了。

demo_app

demo_app接受两个参数environ和start_response,其中environ包含包含所有cgi和wsgi的参数变量,start_response是一个函数,参数为status和headers,返回结果为列表或__iter__的可迭代实例。

复制代码
def demo_app(environ,start_response):
    from StringIO import StringIO
    stdout = StringIO()
    print >>stdout, "Hello world!"
    print >>stdout
    h = environ.items(); h.sort()
    for k,v in h:
        print >>stdout, k,'=', repr(v)
    start_response("200 OK", [('Content-Type','text/plain')])
    return [stdout.getvalue()]
复制代码

实现自己的hello_app,替换demo_app即可。

def hello_app(environ, start_response):
    status = '200 OK'
    response_headers = [('Content-type', 'text/plain')]
    start_response(status, response_headers)
    return ['Hello world!\n']

更多的基础细节请参考:http://www.tuicool.com/articles/aYBRBz

simfish的实现

web框架其实并不复杂,仅仅负责请求的分发和处理,让web后台开发变得简单、规范的一种方法。

本框架主要参考了bottle和webpy的源码。

路由

使用过web框架的人对路由并不陌生,路由就是用来记录url和callback function的映射关系。

在simfish中实现了三种添加路由的方法(装饰器、一次加载、随时添加),源码如下(具体内容参考注释):

复制代码
# Route
class Routes:
    """FrameWork Routes"""
    ROUTES = {} #存储所有的url到callback function的映射

    @classmethod
    def add(cls, url, handler): 
        """add route and handler to ROUTES"""
        if not url.startswith('/'):
            url = '/' + url
        if re.match(r'^/(\w+/)*\w*$', url): #这里需要使用re模块来获取正确的url
            cls.ROUTES[url] = handler

    @classmethod
    def match(cls, url): #用来寻找url对象的处理函数
        """match url in ROUTES"""
        if not url:
            return None
        url = url.strip()
        route = cls.ROUTES.get(url,None) #从ROUTES中查找结果
        return route

    @classmethod
    def load_urls(cls, urls): #用于类似webpy中urls加载的方式
        for item in urls:
            cls.add(item[0], item[1])


def route(url, **kargs): #这是一个装饰器,@route('/')
    """Decorator for request handler. Same as Routes.route(url, handler)."""
    def wrapper(handler):
        Routes.add(url, handler, **kargs)
        return handler
    return wrapper
复制代码

具体使用方法参考:routing

封装request

在demo_app中的参数environ(它是一个字典啊!!!)中包含了request中需要的所有信息,那么我们需要把environ添加到request类中,

class Request(threading.local):
    """Represents a single request using thread-local namespace"""
    def bind(self, environ):
        """Bind the enviroment"""
        self._environ = environ

添加获取请求方方法的方法,使用@propery让method方法可以直接调用,注意保持方法的大写(GET/POST)

@property
def method(self):
    """Returns the request method (GET,POST,PUT,DELETE,...)"""
    return self._environ.get('REQUEST_METHOD', 'GET').upper()

如果获取请求参数呢?在django中使用如下的方法,

request.GET.get('param', '')
request.POST.get('param', '')

那么,我们需要把get和post的参数全部添加到一个字典中,在environ中"QUERY_STRING"包含了get的所有参数,而post的参数需要通过"wsgi.input"获取。

复制代码
@property
def GET(self):
    """Returns a dict with GET parameters."""
    if self._GET is None:
        raw_dict = parse_qs(self.query_string, keep_blank_values=1)
        self._GET = {}
        for key, value in raw_dict.items():
            if len(value) == 1:
                self._GET[key] = value[0]
            else:
                self._GET[key] = value
    return self._GET
复制代码

其中,parse_qs是解析get参数的,推荐使用urlparse.parse_qs 和 urlparse.parse_qsl,目前cgi的已经废弃但保留是为了向后兼容。

与get请求不同之处,在post请求中需要调用cgi模块的FieldStorage来解析post请求参数。

raw_data = cgi.FieldStorage(fp=self._environ['wsgi.input'], environ=self._environ)

具体参考源码:simfish.py

封装response

在这里主要实现了response-header和response-status的封装。

复制代码
class Response(threading.local):
    """Represents a single response using thread-local namespace."""
    def bind(self):
        """Clears old data and creates a brand new Response object"""
        self.status = 200
        self.header = HeaderDict() #继承dict的header类
        self.header['Content-type'] = 'text/plain'
复制代码

继承自threading.local可以保证每个每个线程拥有自己的request和response,并不会相互影响。

实现template

这里使用bottle默认的模板,使用方法参考:template

发送文件

文件的发送与普通的string返回并不相同。首先,需要判断文件的权限,

复制代码
if not filename.startswith(root):
        response.status = 401
        return "Access denied."
    if not os.path.exists(filename) or not os.path.isfile(filename):
        response.status = 404
        return "File does not exist."
    if not os.access(filename, os.R_OK):
        response.status = 401
        return "You do not have permission to access this file."
复制代码

获取文件的类型,这里需要使用mimetypes模块,

if mimetype:
    response.header['Content-type'] = mimetype
elif guessmime:
    guess = mimetypes.guess_type(filename)[0]
    if guess:
        response.header['Content-type'] = guess

最后返回文件对象

复制代码
if mimetype == 'application/octet-stream' and "Content-Disposition" not in response.header:
    response.header["Content-Disposition"] = "attachment;filename=%s"%name
elif 'Last-Modified' not in response.header:
    ts = time.gmtime(stats.st_mtime)
    ts = time.strftime("%a, %d %b %Y %H:%M:%S +0000", ts)
    response.header["Content-Length"] = stats.st_size
    response.header['Last-Modified'] = ts
return open(filename, 'r')
复制代码

跳转

# Redirect to another url
def redirect(url, code=307):
    """ Aborts execution and causes a 307 redirect """
    response.status = code
    response.header['Location'] = url
    raise SimFishException("")

异常处理

复制代码
# Exceptions
class SimFishException(Exception):
    """A base class for exception"""
    pass

class HTTPError(SimFishException):
    """Jump out to error handler"""
    def __init__(self, status, text):
        self.output = text
        self.http_status = status

    def __str__(self):
        return self.output

class BreakSimFish(SimFishException):
    """Jump out of execution"""
    def __init__(self, text):
        self.output = text
复制代码

路由分发

在上面已经有了如何添加路由,接下来就要实现路由的分发。

复制代码
class Simfish:
    def __init__(self, environ, start_response):
        self.environ = environ
        self.start = start_response
        request.bind(environ) #绑定request和response
        response.bind()

    def __iter__(self):
        path = request.path
        handler = Routes.match(path) #Routes类中的match方法,获取处理的callback function
        result = ""
        if not handler:
            response.status = 404
            result = "not Found"
        else:
            try:
                result = handler(request)
            except SimFishException,output: #捕获异常情况
                result = output
        if isinstance(result, tuple) and len(result) == 2: #返回(response_string, mimetype),自定义返回类型
            response.header['Content-type'] = result[1]
            result = result[0]
        status = '%d %s' % (response.status, HTTP_CODES[response.status]) #获取返回status
        self.start(status, list(response.header.items())) #调用start_response
        
        if hasattr(result, 'read'): #用于返回文件
            if 'wsgi.file_wrapper' in self.environ:
                return self.environ['wsgi.file_wrapper'](result)
            else:
                return iter(lambda: result.read(8192), '')
            return iter(lambda: result.read(8192), '')
        elif isinstance(result, basestring):
            return iter([result])
        else:
            return iter(result)
复制代码

实例

复制代码
#!/usr/bin/env python
# encoding:utf8

from simfish import application, route

@route('/')
def hello(request):
    return "hello world"

app = application(port=8086)
app.run()
复制代码


本文转自cococo点点博客园博客,原文链接:http://www.cnblogs.com/coder2012/p/4457473.html,如需转载请自行联系原作者
相关文章
|
8天前
|
前端开发 JavaScript 安全
深入理解Python Web开发中的前后端分离与WebSocket实时通信技术
在现代Web开发中,前后端分离已成为主流架构,通过解耦前端(用户界面)与后端(服务逻辑),提升了开发效率和团队协作。前端使用Vue.js、React等框架与后端通过HTTP/HTTPS通信,而WebSocket则实现了低延迟的全双工实时通信。本文结合Python框架如Flask和Django,探讨了前后端分离与WebSocket的最佳实践,包括明确接口规范、安全性考虑、性能优化及错误处理等方面,助力构建高效、实时且安全的Web应用。
22 2
|
8天前
|
前端开发 Python
前后端分离的进化:Python Web项目中的WebSocket实时通信解决方案
在现代Web开发领域,前后端分离已成为一种主流架构模式,它促进了开发效率、提升了应用的可维护性和可扩展性。随着实时数据交互需求的日益增长,WebSocket作为一种在单个长连接上进行全双工通讯的协议,成为了实现前后端实时通信的理想选择。在Python Web项目中,结合Flask框架与Flask-SocketIO库,我们可以轻松实现WebSocket的实时通信功能。
22 2
|
8天前
|
JavaScript 前端开发 UED
WebSocket在Python Web开发中的革新应用:解锁实时通信的新可能
在快速发展的Web应用领域中,实时通信已成为许多现代应用不可或缺的功能。传统的HTTP请求/响应模式在处理实时数据时显得力不从心,而WebSocket技术的出现,为Python Web开发带来了革命性的变化,它允许服务器与客户端之间建立持久的连接,从而实现了数据的即时传输与交换。本文将通过问题解答的形式,深入探讨WebSocket在Python Web开发中的革新应用及其实现方法。
22 3
|
8天前
|
前端开发 开发者 Python
从零到一:Python Web框架中的模板引擎入门与进阶
在Web开发的广阔世界里,模板引擎是连接后端逻辑与前端展示的重要桥梁。对于Python Web开发者而言,掌握模板引擎的使用是从零到一构建动态网站或应用不可或缺的一步。本文将带你从基础入门到进阶应用,深入了解Python Web框架中的模板引擎。
14 3
|
8天前
|
数据库 开发者 Python
实战指南:用Python协程与异步函数优化高性能Web应用
在快速发展的Web开发领域,高性能与高效响应是衡量应用质量的重要标准。随着Python在Web开发中的广泛应用,如何利用Python的协程(Coroutine)与异步函数(Async Functions)特性来优化Web应用的性能,成为了许多开发者关注的焦点。本文将从实战角度出发,通过具体案例展示如何运用这些技术来提升Web应用的响应速度和吞吐量。
12 1
|
12天前
|
SQL 安全 数据库
惊!Python Web安全黑洞大曝光:SQL注入、XSS、CSRF,你中招了吗?
在数字化时代,Web应用的安全性至关重要。许多Python开发者在追求功能时,常忽视SQL注入、XSS和CSRF等安全威胁。本文将深入剖析这些风险并提供最佳实践:使用参数化查询预防SQL注入;通过HTML转义阻止XSS攻击;在表单中加入CSRF令牌增强安全性。遵循这些方法,可有效提升Web应用的安全防护水平,保护用户数据与隐私。安全需持续关注与改进,每个细节都至关重要。
46 5
|
11天前
|
存储 JSON API
实战派教程!Python Web开发中RESTful API的设计哲学与实现技巧,一网打尽!
在数字化时代,Web API成为连接前后端及构建复杂应用的关键。RESTful API因简洁直观而广受欢迎。本文通过实战案例,介绍Python Web开发中的RESTful API设计哲学与技巧,包括使用Flask框架构建一个图书管理系统的API,涵盖资源定义、请求响应设计及实现示例。通过准确使用HTTP状态码、版本控制、错误处理及文档化等技巧,帮助你深入理解RESTful API的设计与实现。希望本文能助力你的API设计之旅。
34 3
|
12天前
|
中间件 API 开发者
深入理解Python Web框架:中间件的工作原理与应用策略
在Python Web开发中,中间件位于请求处理的关键位置,提供强大的扩展能力。本文通过问答形式,探讨中间件的工作原理、应用场景及实践策略,并以Flask和Django为例展示具体实现。中间件可以在请求到达视图前或响应返回后执行代码,实现日志记录、权限验证等功能。Flask通过装饰器模拟中间件行为,而Django则提供官方中间件系统,允许在不同阶段扩展功能。合理制定中间件策略能显著提升应用的灵活性和可扩展性。
15 4
|
12天前
|
JSON API 数据库
从零到英雄?一篇文章带你搞定Python Web开发中的RESTful API实现!
在Python的Web开发领域中,RESTful API是核心技能之一。本教程将从零开始,通过实战案例教你如何使用Flask框架搭建RESTful API。首先确保已安装Python和Flask,接着通过创建一个简单的用户管理系统,逐步实现用户信息的增删改查(CRUD)操作。我们将定义路由并处理HTTP请求,最终构建出功能完整的Web服务。无论是初学者还是有经验的开发者,都能从中受益,迈出成为Web开发高手的重要一步。
35 4
|
10天前
|
缓存 中间件 网络架构
Python Web开发实战:高效利用路由与中间件提升应用性能
在Python Web开发中,路由和中间件是构建高效、可扩展应用的核心组件。路由通过装饰器如`@app.route()`将HTTP请求映射到处理函数;中间件则在请求处理流程中插入自定义逻辑,如日志记录和验证。合理设计路由和中间件能显著提升应用性能和可维护性。本文以Flask为例,详细介绍如何优化路由、避免冲突、使用蓝图管理大型应用,并通过中间件实现缓存、请求验证及异常处理等功能,帮助你构建快速且健壮的Web应用。
11 1
下一篇
无影云桌面