python基础教程运行程序_Python入门基础教程:WSGI
原标题:Python入门基础教程:WSGI
WSGI 简介
WSGI 是什么
WSGI 是 Python Web Server Gateway Interface 的缩写,是描述 Web 服务器与 Python 应用程序之间如何交互的接口规范。该规范具体描述在 PEP-3333。
这个规范相当于 Web 服务器和 Python 应用程序之间的桥梁。对于 Web 服务器,WSGI 描述了如何把用户的请求数据交给 Python 应用程序;对于 Python 应用程序,WSGI 描述了如何获得用户的请求数据,如何将请求的处理结果返回给 Web 服务器。
WSGI 应用程序
符合 WSGI 规范的 Python 应用程序必须是:
一个可调用对象(callable object,例如函数、类、实现了 __call__ 方法的实例)
接受两个由 WSGI Server 提供的参数:
environ 字典,包含 环境变量,请求数据,如 REQUEST_METHOD,PATH_INFO,QUERY_STRING 等
start_response 函数,开始响应请求的回调函数,用于发送响应状态(HTTP status) 和响应头(HTTP headers)
返回一个由 bytes 类型元素组成的可迭代对象(通常是一个字节序列),即响应正文(Response body)
下面分别以函数、类、实现了 __call__ 方法的实例来演示符合 WSGI 规范的 Python 应用程序:
# 可调用对象是一个函数
def simple_app(environ, start_response):
# 响应状态(状态码和状态信息)
status = '200 OK'
# 响应体
response_body = b"Hello WSGI"
# 响应头,是一个列表,每对键值都必须是一个 tuple
response_headers = [('Content-type', 'text/plain'),
('Content-Length', str(len(response_body)))]
# 回调 WSGI 服务器提供的 start_response,返回响应状态和响应头
start_response(status, response_headers)
# 返回响应体,由 bytes 类型元素组成的可迭代对象
return [response_body]
# 可调用对象是一个类
class AppClass:
"""可调用对象是 AppClass 类,调用方法:
for body in AppClass(env, start_response):
process_body(body)
"""
def __init__(self, environ, start_response):
self.environ = environ
self.start = start_response
def __iter__(self):
status = '200 OK'
response_body = b"Hello WSGI"
response_headers = [('Content-type', 'text/plain'),
('Content-Length', str(len(response_body)))]
self.start(status, response_headers)
yield response_body
# 可调用对象是一个类实例
class AnotherAppClass:
"""可调用对象是 AnotherAppClass 类实例,调用方法:
app = AnotherAppClass()
for body in app(env, start_response):
process_body(body)
"""
def __init__(self):
pass
def __call__(self, environ, start_response):
status = '200 OK'
response_body = b"Hello WSGI"
response_headers = [('Content-type', 'text/plain'),
('Content-Length', str(len(response_body)))]
start_response(status, response_headers)
yield response_body
WSGI 服务器
跟 WSGI 应用程序对应的 WSGI 服务器需要完成以下工作:
接收 HTTP 请求,返回 HTTP 响应
提供 environ 数据,实现回调函数 start_response
调用 WSGI application,并将 environ,start_response 作为参数传入
简化版 WSGI 服务器内部的实现流程:
import os, sys
def unicode_to_wsgi(u):
return u.decode('utf-8')
def wsgi_to_bytes(s):
return s.encode('utf-8')
# application 是 WSGI 应用程序,一个可调用对象
def run_with_cgi(application):
# 准备 environ 参数数据
# 内部包含本次 HTTP 请求的数据,如 REQUEST_METHOD, PATH_INFO, QUERY_STRING 等
environ = {k: unicode_to_wsgi(v) for k,v in os.environ.items()}
# WSGI 环境变量
environ['wsgi.input'] = sys.stdin.buffer
environ['wsgi.errors'] = sys.stderr
environ['wsgi.version'] = (1, 0)
environ['wsgi.multithread'] = False
environ['wsgi.multiprocess'] = True
environ['wsgi.run_once'] = True
if environ.get('HTTPS', 'off') in ('on', '1'):
environ['wsgi.url_scheme'] = 'https'
else:
environ['wsgi.url_scheme'] = 'http'
headers_set = []
headers_sent = []
def write(data):
out = sys.stdout.buffer
if not headers_set:
raise Asserti("write() before start_response()")
elif not headers_sent:
# 在第一次发送响应体之前,发送已经存在的响应头
status, response_headers = headers_sent[:] = headers_set
out.write(wsgi_to_bytes('Status: %s\r\n' % status))
for header in response_headers:
out.write(wsgi_to_bytes('%s: %s\r\n' % header))
out.write(wsgi_to_bytes('\r\n'))
out.write(data)
out.flush()
# start_response 回调函数,根据 WSGI 应用程序传递过来的 HTTP status 和 response_headers
# 设置响应状态和响应头
def start_response(status, response_headers, exc_info=None):
# 处理异常情况
if exc_info:
pass
headers_set[:] = [status, response_headers]
return write
# 调用 WSGI 应用程序,传入准备好的 environ(请求数据)和 start_response(开始响应回调函数)
result = application(environ, start_response)
# 处理响应体
try:
for data in result:
if data:
write(data)
finally:
if hasattr(result, 'close'):
result.close()
Middleware
Middleware(中间件) 处于 WSGI 服务器和 WSGI 应用程序之间。对于 WSGI 应用程序它相当于 WSGI 服务器,而对于 WSGI 服务器 它相当于 WSGI 应用程序。它很像 WSGI 应用程序,接收到请求之后,做一些针对请求的处理,同时它又能在接收到响应之后,做一些针对响应的处理。所以 Middleware 的特点是:
被 WSGI 服务器或其他 Middleware 调用,返回 WSGI 应用程序
调用 WSGI 应用程序,传入 environ 和 start_response
我们以白名单过滤和响应后续处理来演示 Middleware:
from wsgiref.simple_server import make_server
def app(environ, start_response):
# 响应状态(状态码和状态信息)
status = '200 OK'
# 响应体
response_body = b"Hello WSGI"
# 响应头,是一个列表,每对键值都必须是一个 tuple
response_headers = [('Content-type', 'text/plain'),
('Content-Length', str(len(response_body)))]
# 回调 WSGI 服务器提供的 start_response,返回响应状态和响应头
start_response(status, response_headers)
# 返回响应体,由 bytes 类型元素组成的可迭代对象
return [response_body]
# 针对请求数据进行处理的中间件
class WhitelistMiddleware(object):
def __init__(self, app):
self.app = app
# 类实例被调用时,根据从请求中获得的 HTTP_HOST 实现白名单功能
def __call__(self, environ, start_response):
ip_addr = environ.get('HTTP_HOST').split(':')[0]
if ip_addr not in ('127.0.0.1'):
start_response('403 Forbidden', [('Content-Type', 'text/plain')])
return [b'Forbidden']
return self.app(environ, start_response)
# 针对响应数据进行处理的中间件
class UpperMiddleware(object):
def __init__(self, app):
self.app = app
# 类实例被调用时,将响应体的内容转换成大写格式
def __call__(self, environ, start_response):
for data in self.app(environ, start_response):
yield data.upper()
if __name__ == '__main__':
app = UpperMiddleware(WhitelistMiddleware(app))
with make_server('', 8000, app) as httpd:
print("Serving on port 8000...")
httpd.serve_forever()
上面例子是一份完整可运行的代码。函数 app 是 WSGI 应用程序,WhitelistMiddleware 和 UpperMiddleware 是 WSGI Middleware,WSGI 服务器使用的是 Python 内置的 wsgiref 模块(wsgiref 模块是 Python 3 提供的 WSGI 规范的参考实现,wsgiref 中的 WSGI 服务器可用于开发测试,不能使用在生产环境)。
在 WSGI 规范中给出了一些 Middleware 的使用场景,其中根据请求路径分发到不同应用程序的场景,正是一个 Web Framework 最基本的一项功能。下面我们来看一个通过 Middleware 实现的路由转发例子:
from wsgiref.simple_server import make_server
# 请求 path 分发中间件
class RouterMiddleware(object):
def __init__(self):
# 保存 path 与应用程序对应关系的字典
self.path_info = {}
def route(self, environ, start_response):
application = self.path_info[environ['PATH_INFO']]
return application(environ, start_response)
# 类实例被调用时,保存 path 和应用程序对应关系
def __call__(self, path):
def wrapper(application):
self.path_info[path] = application
return wrapper
router = RouterMiddleware()
@router('/hello') # 调用 RouterMiddleware 类实例,保存 path 和应用程序对应关系
def hello(environ, start_response):
status = '200 OK'
response_body = b"Hello"
response_headers = [('Content-type', 'text/plain'),
('Content-Length', str(len(response_body)))]
start_response(status, response_headers)
return [response_body]
@router('/world')
def world(environ, start_response):
status = '200 OK'
response_body = b'World'
response_headers = [('Content-type', 'text/plain'),
('Content-Length', str(len(response_body)))]
start_response(status, response_headers)
return [response_body]
@router('/')
def hello_world(environ, start_response):
status = '200 OK'
response_body = b'Hello World'
response_headers = [('Content-type', 'text/plain'),
('Content-Length', str(len(response_body)))]
start_response(status, response_headers)
return [response_body]
def app(environ, start_response):
return router.route(environ, start_response)
if __name__ == '__main__':
with make_server('', 8000, app) as httpd:
print("Serving on port 8000...")
httpd.serve_forever()
WSGI 接口规范描述的 WSGI 应用程序太过于底层,对于开发人员很不友好。人们通常会使用 Web Framework 来完成一个 Web 应用的开发工作,然后会把这个 Web 应用部署在为生产环境准备的 Web 服务器上。
常用的 Python Web Framework:
Django
一个功能完备的 Web 框架,拥有庞大的开发者社区和丰富的第三方库。
Flask
一款微型框架,构建更小应用、API 和 web 服务。是任何不适用 Django 的 Python web 应用的默认选择。
Tornado
一个异步 web 框架,原生支持 WebSocket。
Bottle
更小的 Web 框架,整个框架只有一个 Python 文件,是不错的源码学习案例。
常用的 WSGI Web Server:
Gunicorn
纯 Python 实现的 WSGI 服务器,拥有十分简单的配置和十分合理的默认配置,使用简单。
uWSGI
基于 uwsgi 协议的,功能十分强大的 Web 服务器,同时也支持 Python WSGI 协议。性能很好,但配置复杂。
责任编辑:
python基础教程运行程序_Python入门基础教程:WSGI相关推荐
- python监控linux运行程序_python linux监控程序
Pyinotify – Linux中实时监控文件系统更改 Pyinotify 是一个简单而实用的 Python 模块,它用于通过 inotify 实时监控Linux文件系统的更改.用于在Linux中实 ...
- python创建对象的格式为_Python入门基础学习(面向对象)
python基础学习笔记(四) 面向对象的三个基本特征: 封装:把客观事物抽象并封装成对象,即将属性,方法和事件等集合在一个整体内 继承:允许使用现有类的功能并在无须重新改写原来的类情况下,对这些功能 ...
- python列表元素为中文_python入门基础教程之Python list列表修改元素
python提供了两种修改列表(list)元素的方法,你可以每次修改单个元素,也可以每次修改一组元素(多个). 修改单个元素 修改单个元素非常简单,直接对元素赋值即可.请看下面的例子: nums = ...
- python unicode编码转换中文_Python入门高级教程--Python 中文编码
Python 中文编码 前面章节中我们已经学会了如何用 Python 输出 "Hello, World!",英文没有问题,但是如果你输出中文字符 "你好,世界" ...
- python代码变成运行程序_python脚本转化单个exe执行程序
操作系统平台: Windows Server 2003 R2 Enterprise SP2 X86简体中文版 1.ActivePython-2.7.5.6-win32-x86.msi 2.setupt ...
- python绿色版运行程序_Python打包exe运行程序,分享你的技术成果!
本文转载于公众号:你想要
- 匹配正则_程序员入门基础:python正则表达式贪婪匹配和非贪婪匹配
此文为python正则表达式的高阶入门,正则基础入门请参考程序员入门基础:python的正则表达式. 一.贪婪匹配和非贪婪匹配 举例说明概念: print('非贪婪匹配',re.search('el+ ...
- 好程序员web前端教程分享web前端入门基础知识
好程序员web前端教程分享web前端入门基础知识,作为合格的Web前端工程师必须得掌握HTML.CSS和JavaScript.只懂其中一两个还不行,必须对这三门语言都要熟悉.下面我们一起来看一看吧! ...
- 视频教程-微信小程序从入门基础(第一季)-PHP
微信小程序从入门基础(第一季) 多年一线互联网开发实战以及培训经验,对php开发,linux运维架构有丰富的经验,善于分析问题,解决问题. lampol ¥117.00 立即订阅 扫码下载「CSDN程 ...
最新文章
- gamma函数及相关其分布
- run-time cloud server system development recode
- LeetCode5-最长回文子串原理及Python实现
- jquery pager 访问 java_基于JQuery的Pager分页器实现代码
- Salesforce LWC学习(二) helloWorld程序在VSCode中的实现
- go url 参数编码和解码
- 详解animate.css动画插件用法
- 用C 程序理解汉字的机内码表示
- 网卡不兼容linux系统,CentOS与Broadcom 5709兼容性问题导致业务网络中断
- 计算机资源管理器总是未响应,资源管理器总是无响应,而且开机很慢老是解决不了问题...
- 【顺序、分支、循环、子程序设计】—— 微机原理实验
- 一大波无门槛优惠券来袭(仅限300张)
- 10分钟搭建一个免费个人博客网站
- 表格提示html内容消失,如何解决Word里面的表格插入题注后页面上内容消失、无法编辑的问题...
- Linux操作系统——切换到root用户及其他用户
- Anaconda的升级与卸载
- win10下禁止自动更新,Window Update禁用无效后续方法
- ORACLE exp时出现1455错误,全网唯一正解,建议收藏
- 印度进口战斗机想退货,因系统无法识别自家口音
- 开学季都有哪些数码产品推荐?2022年数码好物推荐