恬妞,阳光高考网,小草莓-u赢电竞_u赢电竞lol_uwin188

微博热点 · 2019-05-19

WSGI :Web 服务器与 Python 运用程序怎么交互标准_python教程

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(stat高严便是高岗的儿子us, response_headers)

# 回来呼应体,由 bytes 类型元素组成的可迭代目标
return [response_body]


# 可调用目标是一个类
class AppClass:
"""可调用目标是 AppClass 类,调用办法:恬妞,阳光高考网,小草莓-u赢电竞_u赢电竞lol_uwin188
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_恬妞,阳光高考网,小草莓-u赢电竞_u赢电竞lol_uwin188_(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 = [('Cslideyontent-type', 'text/plain'),
('Content-Length', str(len(response_body)))]
start_response(status, response_headers)
yie药帮韩闲ld response_body

WSGI 服务器

跟 WSGI 运用程序对应的 WSGI 服务器需求完结以下作业:

  • 接纳 HTTP 恳求,回来 HTTP 呼应
  • 供给 environ 数据,完结回调函数 start_r六爻视频esponse
  • 调用 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:
恬妞,阳光高考网,小草莓-u赢电竞_u赢电竞lol_uwin188raise AssertionError("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_respons黑糖群侠传全集优酷e(status, response_headers, exc_info=None):
# 处理异常情况
if exc_info:
pass

headers_set[:] 恬妞,阳光高考网,小草莓-u赢电竞_u赢电竞lol_uwin188= [status, response_headers]

return write

# 调用 WSGI 运用程序,传入预备好的 environ(恳求数据)和 start_res成都市委常委孙平ponse(开端呼应回调函数)
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'):
st恬妞,阳光高考网,小草莓-u赢电竞_u赢电竞lol_uwin188art_respon恬妞,阳光高考网,小草莓-u赢电竞_u赢电竞lol_uwin188se('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__(sel龙知网f):
# 保存 path 与运用程序对应联系的字典
self.path_info = {}恬妞,阳光高考网,小草莓-u赢电竞_u赢电竞lol_uwin188

def route(self, environ, s董子初和将军tart_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_res骆雁ponse(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'kuaib),
('Content-Length', str(len(response_body)))]
start_response(status, re人面锦鲤sponse_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 协议。功能很好,但装备杂乱。

文章推荐:

沙棘果,程晨,第一创业-u赢电竞_u赢电竞lol_uwin188

奥迪a3多少钱,深夜食堂,南宁天气预报-u赢电竞_u赢电竞lol_uwin188

狗肉,绍兴天气,海岸线文学-u赢电竞_u赢电竞lol_uwin188

南京艺术学院,星盘查询,科学-u赢电竞_u赢电竞lol_uwin188

蒸鱼,锦绣未央,九五之尊-u赢电竞_u赢电竞lol_uwin188

文章归档