用python写一个简单的web框架

最近在实验室也没什么事情做,闲着无聊。于是想着造轮子,最后决定写一个简单的web框架玩玩。

STEP.1


我们首先得选择基于什么协议来写这种框架。我们可以选择CGI协议,或者是WSGI接口。如果使用CGI,实际上我们只是按着CGI的规范写了一个python程序,然后每次服务器收到请求,就fork一个程序来执行它,然后返回一个http文档,性能比较低下。对于WSGI,而是一个存在于服务器和应用间的接口,在WSGI之前,web应用都是依赖于服务器的,现在流行的python框架都支持WSGI接口。

STEP.2 PEP-333


这一段是PEP-333 所提供的样例代码。

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']

这里的application被传入了两个值。

  • environ
  • start_response。
    environ是一个字典,保存了http请求的信息。
    start_response是一个函数,发送http响应。她有两个参数status 和 start_headers。
  • status必须是由状态编号和具体信息组成的字符串,必须符合RFC 2616。
  • start_headers是一个(header_name,header_value) 元组的列表元组列表。其中的hearder_name必须是合法的http header字段名。在RFC 2616, Section 4.2中有详细定义。
    当然官方还给出了类的实现。
  def __init__(self, environ, start_response):

        self.environ = environ

        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"

了解了如上信息后,基本上可以开始了。我们就到官方给的代码上进行修改吧。

STEP.3 将路径链接到函数


首先我们得把用户请求的路径,链接到函数。我们可以实现一个getPage方法,专门做这件事。我们所拥有的信息,只有environ['PATH_INFO']。

urls = [('^/index/$','func_index'),
        ('^/comment/$','func_comment'),
        ('^/environ/$','get_environ'),
        ('^/post/$','post_test')]#urls是提供给app开发者来做链接的。
    def getPage(self):
        path = self.environ['PATH_INFO']
        for pattern in self.urls:
            m = re.match(pattern[0],path)#将urls元素的第0项和path进行比对,如果匹配上了,返回函数名
            if m:
                function = getattr(self,pattern[1])#getattr方法来得到函数
                return function()
        return '404 not found'#没匹配上任何东西

写到这里之后,每次添加页面,就只需要在urls列表中添加一个元祖就行了。

STEP.4 获取模版


既然是写web app,模版肯定是得有的。这里我提供了一种getTemplate方法来做这件事。不过我只提供了变量的替换。

    def getTemplate(self,tem_name,rep=0):
        #这个函数返回内容,tem_name是文件名字
        #参数rep是一个字典,默认为0
        f = open('template/'+tem_name)
        html = f.read()
        if(rep!=0):
            for to_replace in rep:
                strinfo = re.compile('\{\%\s*'+str(to_replace)+'\s*\%\}')
                html = strinfo.sub(rep[to_replace],html)
        return html

STEP.5 POST数据的处理


要想获取POST数据,我们得通过environ['wsgi.input']来处理。而他实际上就是系统的标准输入。

 environ['wsgi.input']        = sys.stdin

知道这点后就很好写了。

    def getPost(self):
        if(self.environ['REQUEST_METHOD'] == 'POST'):
            try:
                request_body_size = int(self.environ.get('CONTENT_LENGTH', 0))#读出content_length的值
            except:
                request_body_size = 0
            request_body = self.environ['wsgi.input'].read(request_body_size) #请求的body
            post_data = parse_qs(request_body)#parse_qs是cgi提供的方法,帮助我们处理请求
            return post_data

数据库的链接


import MySQLdb
class Model(object):
    def __init__(self):
            self.host = 'localhost'
            self.port = 3306
            self.user = 'admin'
            self.passwd = 'admin'
            self.db = 'xieyi'
    def build_connect(self):
        self.conn = MySQLdb.connect(
            host = self.host,
            port = self.port,
            user = self.user,
            passwd = self.passwd,
            db = self.db
            )
    def exec_ins(self,ins):
        cur = self.conn.cursor()
        num = cur.execute(ins)
        info = {} 
        if(num>0):
            info = cur.fetchmany(num)
        cur.close()
        self.conn.commit()
        return info 
    def close(self):
        self.conn.close()

STEP.6 清理工作


很多配置如果放到代码中,会增加阅读负担。于是把urls,model抽取出来。
使得配置更加方便。

STEP.7 结束


这只是一个web框架简易的实现,仅供娱乐。如有疏漏,还望指出。
代码po在https://github.com/bloodycoder/skeleton

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,670评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,928评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,926评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,238评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,112评论 4 356
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,138评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,545评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,232评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,496评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,596评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,369评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,226评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,600评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,906评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,185评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,516评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,721评论 2 335

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,497评论 18 139
  • 全文基于Python 2.7 macOS 10.12.2 werkzeug是Python实现的WSGI规范的使用函...
    Noskthing阅读 7,544评论 5 21
  • 全称为Web Server Gateway Interface,即 Web服务器网关接口。是一种标准接口规范,规定...
    超net阅读 3,148评论 0 2
  • 又是源于一个梦。 梦到大学毕业的前夕,寝室里的四个人喝得酩酊大醉,第二天早上,谁都没有叫醒谁,独自收拾着行李,...
    灬You灬阅读 731评论 1 0
  • HTML5是设计师用来打造时尚网站的最流行的编程语言之一,使用起来非常方便,并且能够提供多种功能,例如内置的视觉元...
    鑫韭缘设计阅读 933评论 0 8