wsgiref 源代码分析 --start_response()

2024-04-30 14:32

本文主要是介绍wsgiref 源代码分析 --start_response(),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

http://blog.csdn.net/on_1y/article/details/18818081

http://blog.csdn.net/on_1y/article/details/18803563

wsgi有两方,服务器方 和 应用程序

        ①服务器方:其调用应用程序,给应用程序提供(环境信息)和(回调函数), 这个回调函数是用来将应用程序设置的http header和status等信息传递给服务器方.

②应用程序:用来生成返回的header,body和status,以便返回给服务器方


     用Python语言写的一个符合WSGI的“Hello World”应用程序如下所示:

<span class="kw1" style="color:#ff770;font-weight: bold;">def</span> app<span class="br0">(</span>environ<span class="sy0" style="color:#66cc66;">,</span> start_response<span class="br0">)</span>:start_response<span class="br0">(</span><span class="st0" style="color:#483d8b;">'200 OK'</span><span class="sy0" style="color:#66cc66;">,</span> <span class="br0">[</span><span class="br0">(</span><span class="st0" style="color:#483d8b;">'Content-Type'</span><span class="sy0" style="color:#66cc66;">,</span> <span class="st0" style="color:#483d8b;">'text/plain'</span><span class="br0">)</span><span class="br0">]</span><span class="br0">)</span><span class="kw1" style="color:#ff770;font-weight: bold;">yield</span> <span class="st0" style="color:#483d8b;">"Hello world!<span class="es0" style="color:#0099;font-weight: bold;">\n</span>"</span>

其中

  • 第一行定义了一个名为app的应用程序,接受两个参数,environ和start_response,environ是一个字典包含了CGI中的环境变量,start_response也是一个callable,接受两个必须的参数,status(HTTP状态)和response_headers(响应消息的头)。
  • 第二行调用了start_response,状态指定为“200 OK”,消息头指定为内容类型是“text/plain”
  • 第三行将响应消息的消息体返回。

   那通俗点来将的话:
wsgi中的服务器方:我们可以理解成是webserver,当然这个webserver可以是外置的,比如lighttpd,也可以是python自己写的。
而应用程序说白了就是:请求的统一入口!所有的请求都进入到这个app中来处理! 这个app说白了就是一个函数!!(类中的__call__是一样的道理)

=========================================================================================================

WSGI应用

WSGI应用其实就是一个callable的对象。举一个最简单的例子,假设存在如下的一个应用:

?
1
2
3
4
5
6
7
8
def application(environ, start_response): 
  status = '200 OK' 
  output = 'World!' 
  response_headers = [('Content-type', 'text/plain'), 
                      ('Content-Length', str(12)] 
  write = start_response(status, response_headers) 
  write('Hello '
  return [output]

这个WSGI应用简单的可以用简陋来形容,但是他的确是一个功能完整的WSGI应用。只不过给人留下了太多的疑点,environ是什么?start_response是什么?为什么可以同时用write和return来返回内容?

对于这些疑问,不妨自己猜测一下他的作用。联想到CGI,那么environ可能就是一系列的环境变量,用来表示HTTP请求的信息,比如说method 之类的。start_response,可能是接受HTTP response头信息,然后返回一个write函数,这个write函数可以把HTTP response的body返回给客户端。return自然是将HTTP response的body信息返回。不过这里的write和函数返回有什么区别?会不会是其实外围默认调用write对应用返回值进行处理?而且为什么 应用的返回值是一个列表呢?说明肯定存在一个对应用执行结果的迭代输出过程。难道说他隐含的支持iterator或者generator吗?

等等,应用执行结果?一个应用既然是一个函数,说明肯定有一个对象去执行它,并且可以猜到,这个对象把environ和start_response传给应用,将应用的返回结果输出给客户端。那么这个对象是什么呢?自然就是WSGI容器了。


这里有很多问题貌似没解决:
1:wsgi一端的webserver是什么,这个貌似是很弱智的问题。比如lighttd就是一个webserver,那我们在lighttpd配置文件中可以指定程序的入口脚本(比如index.php).那么所有请求都会转到这个index.php来执行。  那gunicorn呢?其虽然全部都是用python写的,但是原理和lighttpd一样的,内部都是开socket来监听请求,而后将请求转到后端的python脚本中去执行!当然了:其是转到一个函数中去执行而已!所以我们要做的就是实现这个函数,而后将之加载到gunicorn中,而后启动gunicorn即可!!!!

 

WSGI详解

注意:以 点 开始的解释是WSGI规定 必须满足 的。

应用程序

  • 应用程序是可调用对象
  • 可调用对象有两个位置参数
    所谓位置参数就是调用的时候,依靠位置来确定参数的语义,而不是参数名,也就是说服务 器调用应用程序时,应该是这样:

 

application(env, start_response)

而不是这样:

 

application(start_response=start_response, environ=env)

所以,参数名其实是可以随便起的,只不过为了表义清楚,我们起了environ 和 start_response

  • 第一个参数environ是Python内置的dict对象,应用程序可以对这个参数任意修改。
  • environ参数必须包含 WSGI 需要的一些变量(详见后文)
    也可以包含一些扩展参数,命名规范见后文
  • start_response参数是一个可调用对象。接受两个位置参数,一个可选参数。 例如:start_response(status, response_headers, exc_info=None) status参数是状态码,例如 200 OK 。

response_headers参数是一个列表,列表项的形式为(header_name, header_value)。

exc_info参数在错误处理的时候使用。

status和response_headers的具体内容可以参考 HTTP 协议 Response部分

  • start_response必须返回一个可调用对象: write(body_data)
  • 应用程序必须返回一个可迭代对象。
  • 应用程序不应假设返回的可迭代对象被遍历至终止,因为遍历过程可能出现错误。
  • 应用程序必须在第一次返回可迭代数据之前调用 start_response 方法。
    这是因为可迭代数据是 返回数据的 body 部分,在它返回之前,需要使用 start_response 返回  response_headers 数据。

start_response()

start_response是HTTP响应的开始,它的形式为:

 

start_response(status, response_headers, exc_info=None)

返回一个可调用对象,这个可调用对象形式为:

 

write(body_data)

status 表示 HTTP 状态码,例如 "200 OK", "404 Not Found",它们在 RFC 2616中定义,status禁止包含控制字符。

response_headers 是一个列表,列表项是一个二元组: (header_name, heaer_value) , 每个 header_name 都必须是 RFC 2616 4.2 节中定义的HTTP 头部名。header_value  禁止包含控制字符。

另外,服务器程序必须保证正确的headers 被返回给客户端,如果应用程序没有返回headers,服务器必须添加它。

应用程序和middleware禁止使用 HTTP/1.1 中的 "hop-by-hop"特性,以及其它可能影响客户端与服务器永久连接的特性。

start_response 被调用时,服务器应该检查 headers 中的错误,另外,禁止 start_response直接将 response_headers传递给客户端,它必须把它们存储起来,一直到应用程序第一次迭代返回一个非空数据后,才能将response_headers传递给客户端。这其实是在说,HTTP响应body部分必须有数据,不能只返回一个header。

start_response的第三个参数是一个可选参数,exc_info,它必须和Python的 sys.exc_info()返回的数据有相同类型。当处理请求的过程遇到错误时,这个参数会被设置,同时调用 start_response。如果提供了exc_info,但是HTTP headers 还没有输出,那么 start_response需要将当前存储的 HTTP response headers替换成一个新值。但是,如果提供了exc_info,同时 HTTP headers已经输出了,那么 start_response  必须 raise 一个 error。禁止应用程序处理 start_response raise出的 exceptions,应该交给服务器程序处理。

当且仅当提供 exc_info参数时,start_response才可以被调用多于一次。换句话说,要是没提供这个参数,start_response在当前应用程序中调用后,禁止再调用。

为了避免循环引用,start_response实现时需要保证 exc_info在函数调用后不再包含引用。 也就是说start_response用完 exc_info后,需要保证执行一句

 

exc_info = None

这可以通过 try/finally实现。

 

 

这篇关于wsgiref 源代码分析 --start_response()的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/949116

相关文章

MyBatis Plus 中 update_time 字段自动填充失效的原因分析及解决方案(最新整理)

《MyBatisPlus中update_time字段自动填充失效的原因分析及解决方案(最新整理)》在使用MyBatisPlus时,通常我们会在数据库表中设置create_time和update... 目录前言一、问题现象二、原因分析三、总结:常见原因与解决方法对照表四、推荐写法前言在使用 MyBATis

Python主动抛出异常的各种用法和场景分析

《Python主动抛出异常的各种用法和场景分析》在Python中,我们不仅可以捕获和处理异常,还可以主动抛出异常,也就是以类的方式自定义错误的类型和提示信息,这在编程中非常有用,下面我将详细解释主动抛... 目录一、为什么要主动抛出异常?二、基本语法:raise关键字基本示例三、raise的多种用法1. 抛

github打不开的问题分析及解决

《github打不开的问题分析及解决》:本文主要介绍github打不开的问题分析及解决,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、找到github.com域名解析的ip地址二、找到github.global.ssl.fastly.net网址解析的ip地址三

Mysql的主从同步/复制的原理分析

《Mysql的主从同步/复制的原理分析》:本文主要介绍Mysql的主从同步/复制的原理分析,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录为什么要主从同步?mysql主从同步架构有哪些?Mysql主从复制的原理/整体流程级联复制架构为什么好?Mysql主从复制注意

java -jar命令运行 jar包时运行外部依赖jar包的场景分析

《java-jar命令运行jar包时运行外部依赖jar包的场景分析》:本文主要介绍java-jar命令运行jar包时运行外部依赖jar包的场景分析,本文给大家介绍的非常详细,对大家的学习或工作... 目录Java -jar命令运行 jar包时如何运行外部依赖jar包场景:解决:方法一、启动参数添加: -Xb

Apache 高级配置实战之从连接保持到日志分析的完整指南

《Apache高级配置实战之从连接保持到日志分析的完整指南》本文带你从连接保持优化开始,一路走到访问控制和日志管理,最后用AWStats来分析网站数据,对Apache配置日志分析相关知识感兴趣的朋友... 目录Apache 高级配置实战:从连接保持到日志分析的完整指南前言 一、Apache 连接保持 - 性

Linux中的more 和 less区别对比分析

《Linux中的more和less区别对比分析》在Linux/Unix系统中,more和less都是用于分页查看文本文件的命令,但less是more的增强版,功能更强大,:本文主要介绍Linu... 目录1. 基础功能对比2. 常用操作对比less 的操作3. 实际使用示例4. 为什么推荐 less?5.

spring-gateway filters添加自定义过滤器实现流程分析(可插拔)

《spring-gatewayfilters添加自定义过滤器实现流程分析(可插拔)》:本文主要介绍spring-gatewayfilters添加自定义过滤器实现流程分析(可插拔),本文通过实例图... 目录需求背景需求拆解设计流程及作用域逻辑处理代码逻辑需求背景公司要求,通过公司网络代理访问的请求需要做请

Java集成Onlyoffice的示例代码及场景分析

《Java集成Onlyoffice的示例代码及场景分析》:本文主要介绍Java集成Onlyoffice的示例代码及场景分析,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要... 需求场景:实现文档的在线编辑,团队协作总结:两个接口 + 前端页面 + 配置项接口1:一个接口,将o

IDEA下"File is read-only"可能原因分析及"找不到或无法加载主类"的问题

《IDEA下Fileisread-only可能原因分析及找不到或无法加载主类的问题》:本文主要介绍IDEA下Fileisread-only可能原因分析及找不到或无法加载主类的问题,具有很好的参... 目录1.File is read-only”可能原因2.“找不到或无法加载主类”问题的解决总结1.File