本文记录学习WSGI时的一些知识点,值得后续学习中注意。

  wsgi应用接口只要是一个可调用的对象就行,这个可调用的对象需要:

1. 接受两个位置参数:

  a. 包含CGI形式变量的字典;

  b. 应用调用的回调函数,该回调函数的作用是将HTTP响应的状态码和header返回给server。

2. 将响应body部分的内容作为包裹在一个可迭代的对象中的(若干)字符串。

说明:

  1. application 的第一个参数env是一个字典,里面包含了CGI形式的环境变量,该字典是由server基于客户请求填充。

  2. headers在构建的时候,必须遵循以下规则:

    [(Header name1, Header value1), (Header name2, Header value2),]
   响应header和响应HTTP状态码通过应用的第二个参数即回调函数发回给server。

  3.body在构建的时候,必须遵循以下规则:
    [response_body]
  即响应body必须被包裹在可迭代的对象中,同时通过return 语句返回给server.

下面是wsgi.org官方教程中得到一个例子:

  注意environ参数的含义,start_response函数的作用,response_headers和status是由谁返回给server的,response_body需要什么样的形式,如何返回给server等。

from wsgiref.simple_server import make_server

def application( environ, start_response):
# response_body in a list
response_body = ['%s:%s' %(key, value)
for key, value in sorted(environ.items())]
response_body = '\n'.join(response_body)
response_body = ['The Begining\n',
'*' * 30 + '\n',
response_body,
'\n' + '*' * 30 ,
'\nThe End'] content_length = 0
for s in response_body:
content_length += len(s)    #status code and response_headers
status = '200 OK'
response_headers =[('Content-Type', 'text/plain'),
('Content-Length', str(content_length))]
# use callback function to send back status code
# and response headers
start_response(status, response_headers)
# return response body thruogh return statement
  return response_body httpd = make_server('localhost',8051,application)
httpd.handle_request()

  

应用端

HELLO_WORLD = b"Hello world!\n"

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] class AppClass:
"""Produce the same output, but using a class (Note: 'AppClass' is the "application" here, so calling it
returns an instance of 'AppClass', which is then the iterable
return value of the "application callable" as required by
the spec. If we wanted to use *instances* of 'AppClass' as application
objects instead, we would have to implement a '__call__'
method, which would be invoked to execute the application,
and we would need to create an instance for use by the
server or gateway.
""" 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

服务/网关端

import os, sys

enc, esc = sys.getfilesystemencoding(), 'surrogateescape'

def unicode_to_wsgi(u):
# Convert an environment variable to a WSGI "bytes-as-unicode" string
return u.encode(enc, esc).decode('iso-8859-1') def wsgi_to_bytes(s):
return s.encode('iso-8859-1') def run_with_cgi(application):
environ = {k: unicode_to_wsgi(v) for k,v in os.environ.items()}
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 AssertionError("write() before start_response()") elif not headers_sent:
# Before the first output, send the stored headers
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() def start_response(status, response_headers, exc_info=None):
if exc_info:
try:
if headers_sent:
# Re-raise original exception if headers sent
raise exc_info[1].with_traceback(exc_info[2])
finally:
exc_info = None # avoid dangling circular ref
elif headers_set:
raise AssertionError("Headers already set!") headers_set[:] = [status, response_headers] # Note: error checking on the headers should happen here,
# *after* the headers are set. That way, if an error
# occurs, start_response can only be re-called with
# exc_info set. return write result = application(environ, start_response)
try:
for data in result:
if data: # don't send headers until body appears
write(data)
if not headers_sent:
write('') # send headers now if body was empty
finally:
if hasattr(result, 'close'):
result.close()

  

中间件

from piglatin import piglatin

class LatinIter:

    """Transform iterated output to piglatin, if it's okay to do so

    Note that the "okayness" can change until the application yields
its first non-empty bytestring, so 'transform_ok' has to be a mutable
truth value.
""" def __init__(self, result, transform_ok):
if hasattr(result, 'close'):
self.close = result.close
self._next = iter(result).__next__
self.transform_ok = transform_ok def __iter__(self):
return self def __next__(self):
if self.transform_ok:
return piglatin(self._next()) # call must be byte-safe on Py3
else:
return self._next() class Latinator: # by default, don't transform output
transform = False def __init__(self, application):
self.application = application def __call__(self, environ, start_response): transform_ok = [] def start_latin(status, response_headers, exc_info=None): # Reset ok flag, in case this is a repeat call
del transform_ok[:] for name, value in response_headers:
if name.lower() == 'content-type' and value == 'text/plain':
transform_ok.append(True)
# Strip content-length if present, else it'll be wrong
response_headers = [(name, value)
for name, value in response_headers
if name.lower() != 'content-length'
]
break write = start_response(status, response_headers, exc_info) if transform_ok:
def write_latin(data):
write(piglatin(data)) # call must be byte-safe on Py3
return write_latin
else:
return write return LatinIter(self.application(environ, start_latin), transform_ok) # Run foo_app under a Latinator's control, using the example CGI gateway
from foo_app import foo_app
run_with_cgi(Latinator(foo_app))

  

Python WSGI开发随笔的更多相关文章

  1. python Web开发你要理解的WSGI & uwsgi详解

    原文:https://www.jb51.net/article/144852.htm WSGI协议 首先弄清下面几个概念: WSGI:全称是Web Server Gateway Interface,W ...

  2. Python Web开发中,WSGI协议的作用和实现原理详解

    首先理解下面三个概念: WSGI:全称是Web Server Gateway Interface,WSGI不是服务器,python模块,框架,API或者任何软件,只是一种规范,描述web server ...

  3. Python Web开发中的WSGI协议简介

    在Python Web开发中,我们一般使用Flask.Django等web框架来开发应用程序,生产环境中将应用部署到Apache.Nginx等web服务器时,还需要uWSGI或者Gunicorn.一个 ...

  4. Python Web开发最难懂的WSGI协议,到底包含哪些内容?

    原文出处: PythonScientists 我想大部分Python开发者最先接触到的方向是WEB方向(因为总是有开发者希望马上给自己做个博客出来,例如我),既然是WEB,免不了接触到一些WEB框架, ...

  5. 转载:Python Web开发最难懂的WSGI协议,到底包含哪些内容?

    原文:PSC推出的第二篇文章-<Python Web开发最难懂的WSGI协议,到底包含哪些内容?>-2017.9.27 我想大部分Python开发者最先接触到的方向是WEB方向(因为总是有 ...

  6. python - wsgi协议

    wsgi - python web server gateway interface 出现的目的是,为了在 python框架开发的时候,更具有通用性.只要符合 wsgi标准,就可以自由选择服务器(ng ...

  7. 解决基于BAE python+bottle开发上的一系列问题 - artwebs - 博客频道 - CSDN.NET

    解决基于BAE python+bottle开发上的一系列问题 - artwebs - 博客频道 - CSDN.NET 解决基于BAE python+bottle开发上的一系列问题 分类: python ...

  8. 《Python高效开发实战》实战演练——内置Web服务器4

    <Python高效开发实战>实战演练——开发Django站点1 <Python高效开发实战>实战演练——建立应用2 <Python高效开发实战>实战演练——基本视图 ...

  9. (转)python WSGI框架详解

    原文:https://www.cnblogs.com/shijingjing07/p/6407723.html?utm_source=itdadao&utm_medium=referral h ...

随机推荐

  1. 关于 android receiver

    可以在代码文件中声明一个receiver,也可以在manifest中声明一个,前者中的receiver只有在该activity launch起来以后才会监听其所感兴趣的事件,而如果在androidMa ...

  2. 【socket】小项目-智能点餐系统

    系统说明 前段时间做的一个智能点餐系统,从0开始,用时3天,其中调bug(内存拷贝)调了一天,囧,现记一些架构文档 这个系统涉及到的知识点还是挺多的 典型的c/s模式,socket通信 多线程操作 数 ...

  3. JMeter测试工具中的参数化使用[函数助手]

    下面是我使用JMeter测试工具对某项目中的一个http接口进行测试时的配置参数,使用到了JMeter的随机函数: 在发送POST请求时,需要发送json格式的数据,其中使用到JMeter的" ...

  4. ubuntu创建用户命令

    可以用adduser和useradd来添加用户,用userdel来删除用户. 最简单的命令:sudo adduser test会自动同名组,创建/home/test/,从etc/skel/复制文件,并 ...

  5. java版本DbhelperMysql

    package com.hebut.util; import java.sql.Connection; import java.sql.DriverManager; import java.sql.P ...

  6. kvm libvirt 虚拟机管理

    http://www.2cto.com/os/201203/123128.html kvm虚拟机管理一.环境role         hostname    ip                  O ...

  7. poj1703(种类并查集)

    题意:有两个犯罪集团,现在有两种操作,D [a] [b]表示a和b是属于不同犯罪集团的,A [a] [b] 是询问你a和b的关系,如果ab属于同一个犯罪集团,输出In the same gang.   ...

  8. Android仿华为天气绘制刻度盘

    效果图 能够看到这个自己定义控件结合了颜色渐变.动态绘制刻度.动态水球效果.接下来我们就来看看这个效果是怎样一步一步实现的. 開始自己定义控件 和非常多自己定义控件方式一样须要去基础某种View或者某 ...

  9. IoCopyCurrentIrpStackLocationToNext与IoSetCompletionRoutine的深入理解

    1.IoCopyCurrentIrpStackLocationToNext是拷贝本层的IO_STACK_LOCATION 到下一层.在楚狂人的驱动教程中说:如果对irp完成之后的事情有兴趣,并打算在完 ...

  10. 用图片做div背景的列表布局 CSS代码

    思路: 1.因为是竖型列表,所以外层用 相对定位,这样 在不会重叠在一起 relative 2.里面用绝对位置 absolute,覆盖在图片上面 3.这里有个小技巧,我里面有个特效,文字竖立,并向右旋 ...