wsgi初探
大半夜的不睡觉,起来看技术文档,我这是什么精神啊~
ok 本文的大部分内容都是阅读 http://wsgi.readthedocs.org/en/latest/ 得来的。下面开始研究 wsgi
wsgi全名叫 Web Server Gateway Interface.是一个python的标准,定义了python程序应该如何和webserver通信。本文主要分为以下四个部分:
- what is wsgi
- Application Interface
- Environment dictionary
- Response Iterable
- Parsing the Request - Get
- Parsing the Request - Post
what is wsgi
wsgi是python的一个标准,定义了python application与web server通信的接口标准。它不是一个模块,一个程序,也不是一个server。简单的说,如果一个application是按照 wsgi规范写的,一个web server也是按照wsgi规范写的,那么这个application 就可以运行在这个server上。
wsgi的server所做的事情非常简单,就是把client(通常是浏览器) 的request转交给 wsgi application,然后把wsgi application产生的response返回给client。就是这么简单。
wsgi的application则是可以像积木一样堆叠的。比如,wsgi server上面放一个 程序wsgi 程序A, wsgi 程序A上面再放一个wsgi 程序B, wsgi 程序B上面再放一个wsgi 程序C。理论上可以无限的堆叠。对于那些在中间的wsgi 程序,比如A 和 B, 它们就是wsgi middleware。由于它们处于中间,所以它们与上下层通信都需要实现wsgi规范的接口。
application interface
wsgi application的interface需要是一个可以调用的对象,比如function,class或者一个实现了__call__方法的实例(我猜只要一个实例具有__call__方法,我们就可以调用它吧?等下验证一下 -- 经过验证,是这样的)
- 这个可调用对象必须接收下面两个位置参数:
- 一个装有类似于CGI变量的字典对象
- 一个wsgi server提供的回调函数,该函数用来把wsgi application的HTTP status code/message 和HTTP headers发给wsgi server
- 这个可调用对象必须把response body以string的形式放在一个iterable的对象中
如下是一个代码示例:
# This is our application object. It could have any name,
# except when using mod_wsgi where it must be "application"
def application( # It accepts two arguments:
# environ points to a dictionary containing CGI like environment variables
# which is filled by the server for each received request from the client
environ,
# start_response is a callback function supplied by the server
# which will be used to send the HTTP status and headers to the server
start_response): # build the response body possibly using the environ dictionary
response_body = 'The request method was %s' % environ['REQUEST_METHOD'] # HTTP response code and message
status = '200 OK' # These are HTTP headers expected by the client.
# They must be wrapped as a list of tupled pairs:
# [(Header name, Header value)].
response_headers = [('Content-Type', 'text/plain'),
('Content-Length', str(len(response_body)))] # Send them to the server using the supplied function
start_response(status, response_headers) # Return the response body.
# Notice it is wrapped in a list although it could be any iterable.
return [response_body]
这段代码暂时还不能运行,因为我们还没有wsgi server。下一部分会涉及到
Environment dictionary
环境变量字典会包含一些CGI 变量,wsgi server 在收到client的request后根据request填充这个字典。下面的脚本会输出整个字典:
#! /usr/bin/env python # Our tutorial's WSGI server
from wsgiref.simple_server import make_server def application(environ, start_response): # Sorting and stringifying the environment key, value pairs
response_body = ['%s: %s' % (key, value)
for key, value in sorted(environ.items())]
response_body = '\n'.join(response_body) status = '200 OK'
response_headers = [('Content-Type', 'text/plain'),
('Content-Length', str(len(response_body)))]
start_response(status, response_headers) return [response_body] # Instantiate the WSGI server.
# It will receive the request, pass it to the application
# and send the application's response to the client
httpd = make_server(
'localhost', # The host name.
8051, # A port number where to wait for the request.
application # Our application object name, in this case a function.
) # Wait for a single request, serve it and quit.
httpd.handle_request()
Response Iterable
如果把上面application中的return [response_body] 换成了 return response_body。 则会发现程序的响应速度慢了很多。这是因为server会把response_body的字符串整个当做一个iterable的对象。一个字符一个字符的返回给客户端。 所以,一定要把response_body放进可迭代对象中。 另外,如果一个response_body中包含了多个字符串,那么content-length就是所有字符串的字符数量之和。
Parsing the Request - Get
如果在访问上面的application的时候用下面这样的url
http://localhost:8051/?age=10&hobbies=software&hobbies=tunning
那么在environ字典中REQUEST_METHOD 和 QUERY_STRING 就会是GET 与 age=10&hobbies=software&hobbies=tunning。要注意到hobbies出现了2次。这很正常,比如你提交的表单里面可能有checkbox。通过 CGI module 的 parse_qs 函数,可以很方便的解析query string。parse_qs返回的结果是一个字典,key是如age,hobbies这样的键,而值是list 比如 hobbies对应的值是['software','tunning']。
运行下面的代码,再用上面的URL去访问,就可以看到返回解析过的query string
#!/usr/bin/env python from wsgiref.simple_server import make_server
from cgi import parse_qs, escape def application(environ, start_response): # Returns a dictionary containing lists as values.
d = parse_qs(environ['QUERY_STRING']) # In this idiom you must issue a list containing a default value.
age = d.get('age', [''])[0] # Returns the first age value.
hobbies = d.get('hobbies', []) # Returns a list of hobbies. # Always escape user input to avoid script injection
age = escape(age)
hobbies = [escape(hobby) for hobby in hobbies] response_body = 'age is '+age+' hobbies is '+' '.join(hobbies) status = '200 OK' # Now content type is text/html
response_headers = [('Content-Type', 'text/html'),
('Content-Length', str(len(response_body)))]
start_response(status, response_headers) return [response_body] httpd = make_server('localhost', 8051, application)
# Now it is serve_forever() in instead of handle_request().
# In Windows you can kill it in the Task Manager (python.exe).
# In Linux a Ctrl-C will do it.
httpd.serve_forever()
Parsing the Request - Post
如果request是post,那么query string就会在http body中,而不是在URL中。wsgi server在environ字典的wsgi.input这个键对应的value处放了一个类文件对象。这个类文件对象中存放了具体的request string。wsgi server还在environ字典的content_length键对应处放了这个query string的长度。下面的代码解析post request
#!/usr/bin/env python from wsgiref.simple_server import make_server
from cgi import parse_qs, escape def application(environ, start_response): # the environment variable CONTENT_LENGTH may be empty or missing
try:
request_body_size = int(environ.get('CONTENT_LENGTH', 0))
except (ValueError):
request_body_size = 0 # When the method is POST the query string will be sent
# in the HTTP request body which is passed by the WSGI server
# in the file like wsgi.input environment variable.
request_body = environ['wsgi.input'].read(request_body_size)
d = parse_qs(request_body) age = d.get('age', [''])[0] # Returns the first age value.
hobbies = d.get('hobbies', []) # Returns a list of hobbies. # Always escape user input to avoid script injection
age = escape(age)
hobbies = [escape(hobby) for hobby in hobbies] response_body = age+hobbies status = '200 OK' response_headers = [('Content-Type', 'text/html'),
('Content-Length', str(len(response_body)))]
start_response(status, response_headers) return [response_body] httpd = make_server('localhost', 8051, application)
httpd.serve_forever()
wsgi初探的更多相关文章
- gitbook 准备一 [python3 WSGI 初探]
目录 1.wsgi服务样例 2.请求样例 1.wsgi服务样例 # 官网样例 from wsgiref.util import setup_testing_defaults from wsgiref. ...
- WSGI 简介(使用python描述)
WSGI 简介 背景 Python Web 开发中,服务端程序可以分为两个部分,一是服务器程序,二是应用程序.前者负责把客户端请求接收,整理,后者负责具体的逻辑处理.为了方便应用程序的开发,我们把常用 ...
- 什么是RESTful API、WSGI、pecan
RESTful API REST的全称是Representational State Transfer(表征状态转移), 是Roy Fielding在他的博士论文Architectural Style ...
- Django 源码小剖: 初探 WSGI
Django 源码小剖: 初探 WSGI python 作为一种脚本语言, 已经逐渐大量用于 web 后台开发中, 而基于 python 的 web 应用程序框架也越来越多, Bottle, Djan ...
- Flask初探之WSGI
Flask是一个使用 Python 编写的轻量级 Web 应用框架.较其他同类型框架更为灵活.轻便.安全且容易上手.它可以很好地结合MVC模式进行开发,小型团队在短时间内就可以完成功能丰富的中小型网站 ...
- django初探-创建简单的博客系统
django第一步 1. django安装 pip install django print(django.get_version()) 查看django版本 2. 创建项目 打开cmd,进入指定目录 ...
- Django 00-socket、wsgi及初始django学习心得
HTTP基本原理1.http简述:http协议永远都是客户端发起请求,服务端回送请求.客户端和服务端本质上是一个socket客户端和服务端,http协议可以说是基于socket的再上层封装2.http ...
- [py]彻底细究web框架的wsgi+逻辑处理模块
wsgi逻辑结构初探 参考: 这里图很精彩,wsgi写的不错 web框架 = wsgi+逻辑处理app 接收请求,返回对应的内容 python wsgiref实现了wsgi规范. from wsgir ...
- django初探-创建简单的博客系统(一)
django第一步 1. django安装 pip install django print(django.get_version()) 查看django版本 2. 创建项目 打开cmd,进入指定目录 ...
随机推荐
- 锚点、target="page1"、浮标回到顶部(该点未实现,能力不足)
<html> <head> <meta charset="utf-8"> <title>链接</title> <! ...
- php 5.6 版本配置 oracle ddl
1. Windows版PHP内置了Oracle驱动,在ext目录下:php_oci8.dllphp_oci8_11g.dllphp_pdo_oci.dllLinux上如果自己编译的话则添加下面的con ...
- Kafka~服务端几个常用的命令
在Centos上安装和部署完成kafka之后,我们就可以向服务端推消息和消费它了,今天主要聊几个常用的命令,比建立topic,从broken显示所有topics列表,向broken发消息,从broke ...
- EasyUI系列学习(七)-Linkbutton(按钮)
一.加载组件 1.使用class加载 <a href="#" class="easyui-linkbutton">按钮</a> 2.使用 ...
- js中true和false判断
布尔类型里只有这6参数个返回false,其它都为true Boolean(false) // false Boolean(undefined) // false Boolean(null) // fa ...
- Spark学习之编程进阶——累加器与广播(5)
Spark学习之编程进阶--累加器与广播(5) 1. Spark中两种类型的共享变量:累加器(accumulator)与广播变量(broadcast variable).累加器对信息进行聚合,而广播变 ...
- SVN的三种merge方式【转】
SVN的merge操作是为了保证主干(trunk)和分支(branch)同步,merge方式有: 1.Merge a range of revisions(合并一个范围的版本) 2.Reintegra ...
- Windows提高_2.2第二部分:用户区同步
第二部分:用户区同步 同步和互斥 同步:就是按照一定的顺序执行不同的线程 互斥:当一个线程访问某一资源的时候,其它线程不能同时访问 多线程产生的问题 #include <stdio.h> ...
- Spring框架系列(六)--事务Transaction
本文绝大部分内容为转载,原文地址:https://blog.csdn.net/trigl/article/details/50968079 除此之外,后面还有延伸内容 事务在企业日常开发中几乎是一定会 ...
- 怎么让Eclipse对html和js代码自动提示
使用eclipse自带的插件,无需另外安装插件,具体步骤如下1.打开eclipse→Windows→Preferences→Java→Editor→Content Assist修改Auto Activ ...