返回顶部
首页 > 资讯 > 后端开发 > Python >如何用Python写一个简单的Web框架
  • 627
分享到

如何用Python写一个简单的Web框架

2023-06-17 03:06:55 627人浏览 八月长安

Python 官方文档:入门教程 => 点击学习

摘要

如何用python写一个简单的WEB框架,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。一、概述在Python中,WSGI(Web Server Gateway

如何用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 = httpd.Socket.getsockname()  print 'http://{0}:{1}/'.fORMat(*sa)     # Respond to requests until process is killed  httpd.serve_forever()

运行脚本:

$ python code.py  http://0.0.0.0:8086/

打开浏览器,输入http://0.0.0.0:8086/后可以看到:一行”Hello world!” 和 众多环境变量值。

三、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。

The Application/Framework Side 中给出了一个典型的application实现:

#!/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 = httpd.socket.getsockname()      print 'http://{0}:{1}/'.format(*sa)         # Respond to requests until process is killed      httpd.serve_forever()

运行脚本code.py后,访问http://0.0.0.0:8086/就可以看到那行熟悉的句子:Hello world!

四、区分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.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"

然后,增加对URL中path部分的区分处理:

#!/usr/bin/env python  # -*- coding: utf-8 -*-     """application.py"""     class my_app:      def __init__(self, environ, start_response):          self.environ = environ          self.start = start_response         def __iter__(self):          path = self.environ['PATH_INFO']          if path == "/":              return self.GET_index()          elif path == "/hello":              return self.GET_hello()          else:              return self.notfound()         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.environ = environ          self.start = start_response         def __iter__(self): ##########修改点          path = self.environ['PATH_INFO']          method = self.environ['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)             return self.notfound()         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): ##########修改点          self.environ = 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 = self.environ['PATH_INFO']          method = self.environ['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)             return self.notfound()         def header(self, name, value): ##########修改点          self._headers.append((name, value))         def GET_index(self): ##########修改点          self.header('Content-type', 'text/plain')          return "Welcome!\n"         def GET_hello(self, name): ##########修改点          self.header('Content-type', 'text/plain')          return "Hello %s!\n" % name         def notfound(self): ##########修改点          self.status = '404 Not Found'          self.header('Content-type', 'text/plain')          return "Not Found\n"

3、抽象出框架

为了将类my_app抽象成一个独立的框架,需要作出以下修改:

  • 剥离出其中的具体处理细节:urls配置 和 GET_*方法(改成在多个类中实现相应的GET方法)

  • 把方法header实现为类方法(claSSMethod),以方便外部作为功能函数调用

  • 改用 具有__call__方法的 实例 来实现application

修改后的application.py(最终版本):

#!/usr/bin/env python  # -*- coding: utf-8 -*-     """application.py"""     import re     class my_app:      """my simple web framework"""         headers = []         def __init__(self, urls=(), fvars={}):          self._urls = urls          self._fvars = fvars         def __call__(self, environ, start_response):          self._status = '200 OK' # 默认状态OK          del self.headers[:] # 清空上一次的headers             result = self._delegate(environ)          start_response(self._status, self.headers)             # 将返回值result(字符串 或者 字符串列表)转换为迭代对象          if isinstance(result, basestring):              return iter([result])          else:              return iter(result)         def _delegate(self, environ):          path = environ['PATH_INFO']          method = environ['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() # 方法名大写(如GET、POST)                  klass = self._fvars.get(name) # 根据字符串名称查找类对象                  if hasattr(klass, funcname):                      func = getattr(klass, funcname)                      return func(klass(), *args)             return self._notfound()         def _notfound(self):          self._status = '404 Not Found'          self.header('Content-type', 'text/plain')          return "Not Found\n"         @classmethod      def header(cls, name, value):          cls.headers.append((name, value))

对应修改后的code.py(最终版本):

#!/usr/bin/env python  # -*- coding: utf-8 -*-     """code.py"""     from application import my_app     urls = (      ("/", "index"),      ("/hello/(.*)", "hello"),  )     wsgiapp = my_app(urls, globals())     class index:      def GET(self):          my_app.header('Content-type', 'text/plain')          return "Welcome!\n"     class hello:      def GET(self, name):          my_app.header('Content-type', 'text/plain')          return "Hello %s!\n" % name     if __name__ == '__main__':      from wsgiref.simple_server import make_server      httpd = make_server('', 8086, wsgiapp)         sa = httpd.socket.getsockname()      print 'http://{0}:{1}/'.format(*sa)         # Respond to requests until process is killed      httpd.serve_forever()

当然,您还可以在code.py中配置更多的URL映射,并实现相应的类来对请求作出响应。

主要参考了 How to write a web framework in Python(作者 anandology  是web.py代码的两位维护者之一,另一位则是大名鼎鼎却英年早逝的 Aaron Swartz),在此基础上作了一些调整和修改,并掺杂了自己的一些想法。

看完上述内容是否对您有帮助呢?如果还想对相关知识有进一步的了解或阅读更多相关文章,请关注编程网Python频道,感谢您对编程网的支持。

--结束END--

本文标题: 如何用Python写一个简单的Web框架

本文链接: https://lsjlt.com/news/287039.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 如何用Python写一个简单的Web框架
    如何用Python写一个简单的Web框架,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。一、概述在Python中,WSGI(Web Server Gateway ...
    99+
    2023-06-17
  • python实现一个简单的web应用框架
    目录引言写应用框架需要写底层服务器么uwsgi基本使用安装uwsgi配置uwsgiuwsgi常用配置uwsgi启服和停服启动一个demo写一个简单的web应用框架总结引言 本篇文章所...
    99+
    2023-05-18
    python web应用框架 python web
  • 如何用python写一个简单的find命
        对一个运维来说可能会经常去查找目录下的一些文件是否存在,最常用的就是find命令,它不仅可以查找文件也可以查找目录,find命令用法查找文件[root@node1 opt]# find /usr/ -type f -name df/...
    99+
    2023-01-31
    如何用 简单 python
  • 如何使用Python写一个简单的JSONParser
    本篇内容主要讲解“如何使用Python写一个简单的JSONParser”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“如何使用Python写一个简单的JSONParser”吧!JSON Token...
    99+
    2023-07-06
  • 如何用Python写一个简单的通讯录
    目录用Python写一个简单的通讯录一、构思1、定义空列表和一个空字典来存储 2、定义功能选项3、添加通讯录功能4、 循环,调用所有的函数功能二、整体项目演示用Python写一个简单...
    99+
    2024-04-02
  • Python Tornado框架轻松写一个Web应用的全过程
    目录Tornado是什么 安装 试试看使用tornado框架来写一个web application 总结Tornado是什么 学委之前在看Jupyter组件的源码的时候,发现了to...
    99+
    2024-04-02
  • 用Python写一个简单的api接口
    python框架有很多,例如:Flask,Django,FastAPI 等。本文将使用 Flask 来编写 API 接口。 安装Flask 首先,您需要安装 Flask: pip install fl...
    99+
    2023-10-08
    python 后端 flask
  • 用Python编写一个简单的Http S
    原文地址:Write a simple HTTP server in Python http://www.acmesystems.it/python_httpd 例子中源码: https://github.com/tanzi...
    99+
    2023-01-31
    简单 Python Http
  • 如何在Python中实现一个简单的RPC远程过程调用框架
    如何在Python中实现一个简单的RPC远程过程调用框架在分布式系统中,一种常见的通信机制是通过RPC(Remote Procedure Call,远程过程调用)来实现不同进程之间的函数调用。RPC允许开发者像调用本地函数一样调用远程函数,...
    99+
    2023-10-27
    远程调用 Python RPC框架 实现RPC
  • 用Python写一个简单公众号
      前言:虽然简单,但是稍稍还是有点可取的地方的,终于可以有一个可以作为项目放在自己的github上了T_T,一个好项目一定是可拔插好扩展的,离好项目至少60%吧,以后再进一步完善了。   说实话,有一个微信公众号还是蛮方便的,可以将一些自...
    99+
    2023-01-31
    公众 简单 Python
  • 分享一个简单的java爬虫框架
    反复给网站编写不同的爬虫逻辑太麻烦了,自己实现了一个小框架可以自定义的部分有:请求方式(默认为Getuser-agent为谷歌浏览器的设置),可以通过实现RequestSet接口来自定义请求方式储存方式(默认储存在f盘的html文件夹下),...
    99+
    2023-05-30
    java 爬虫框架 ava
  • 我的第一个python web开发框架(
      前面ORM模块我们已经完成了开发,接下来要做的就是对项目代码进行重构了。因为对底层数据库操作模块(db_helper.py)进行了改造,之前项目的接口代码全都跑不起来了。   在写ORM模块时,我们已经对产品接口的分页查询、新增、修改...
    99+
    2023-01-30
    第一个 框架 python
  • 教你使用Python写一个简单的JSONParser
    目录引言JSON TokenizerJSON Parser引言 最近在学习 Python 的正则表达式内容,我看的是官方的文档,在文档的最后有一个例子,勾起了我的兴趣。它是用正则表达...
    99+
    2023-05-14
    Python JSONParser 简单 JSONParser
  • 怎么使用Python写一个简单的JSONParser
    JSON TokenizerJSON 的词法分析,我主要是参考上面这个截图里面的方式,自己写了一个简单的示例。写得比较简单,应该说它只能支持 JSON 的一个简单子集。这里 TOKEN 的种类,参考了 https://json.org,不过...
    99+
    2023-05-14
    Python
  • python的简单web框架flask快速实现详解
    目录简介web框架的重要组成部分快速上手flaskflask的第一个应用flask中的路由不同的http方法静态文件使用模板总结简介 python可以做很多事情,虽然它的强项在于进...
    99+
    2023-02-07
    python web框架flask python web框架
  • 写一个简单的webserver
    基于 Python3 写的极简版 webserver。用于学习 HTTP协议,及 WEB服务器 工作原理。笔者对 WEB服务器 的工作原理理解的比较粗浅,仅是基于个人的理解来写的,存在很多不足和漏洞,目的在于给大家提供一个写 webser...
    99+
    2023-01-31
    简单 webserver
  • 如何编写一个VBScript简单的页面
    这篇文章主要介绍“如何编写一个VBScript简单的页面”,在日常操作中,相信很多人在如何编写一个VBScript简单的页面问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”如何编写一个VBScript简单的页面...
    99+
    2023-06-09
  • python简单的病毒编程代码,如何用python写一个病毒
    大家好,本文将围绕python简单的病毒编程代码展开说明,如何用python做恶搞病毒是一个很多人都想弄明白的事情,想搞清楚如何用python写一个病毒需要先了解以下几个事情。 1、Python能不能写病毒 国家计算机病毒应急处理中心通...
    99+
    2023-09-08
    小发猫
  • 怎么用Python编写一个简单的游戏
    本篇内容介绍了“怎么用Python编写一个简单的游戏”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!在这个系列中,我们要用不同的编程语言编写相...
    99+
    2023-06-15
  • 用python写一个简单的倒计时软件
    模块:time import time count = 0 a = int(input('time:')) while (count < a): count_now = a - count print(cou...
    99+
    2023-01-31
    倒计时 简单 软件
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作