在线客服 联系我们 返回顶部
企业动态 技术分享 行业动态

Python WSGI的深入理解

2019-08-09

什么是WSGI

WSGI的全称是Web Server Gateway Interface,这是一个规范,描述了web server如何与web application交互、web application如何处理请求。该规范的具体描述在。注意,WSGI既要实现web server,也要实现web application。

实现了WSGI的模块/库有、、等,具体可见。

当前运行在WSGI之上的web框架有Bottle、Flask、Django等,具体可见。

WSGI server所做的工作仅仅是将从客户端收到的请求传递给WSGI application,然后将WSGI application的返回值作为响应传给客户端。WSGI applications 可以是栈式的,这个栈的中间部分叫做中间件,两端是必须要实现的application和server。

WSGI教程

这部分内容主要来自。

WSGI application接口

WSGI application接口应该实现为一个可调用对象,例如函数、方法、类、含__call__方法的实例。这个可调用对象可以接收2个参数:

同时,可调用对象的返回值是响应正文,响应正文是可迭代的、并包含了多个字符串。

WSGI application结构如下:

def application :
 response_body = 'Request method: %s' % environ['REQUEST_METHOD']
 # HTTP响应状态
 status = '200 OK'
 # HTTP响应头,注意格式
 response_headers = [
 ,
 ))
 # 将响应状态和响应头交给WSGI server
 start_response
 # 返回响应正文
 return [response_body]

Environment

下面的程序可以将environment字典的内容返回给客户端:

# ! /usr/bin/env python
# -*- coding: utf-8 -*- 
# 导入python内置的WSGI server
from wsgiref._______server import make_server
def application :
 response_body = [
 '%s: %s' %  for key, value in sorted)
 response_body = '
'.join # 由于下面将Content-Type设置为text/plain,所以`
`在浏览器中会起到换行的作用
 status = '200 OK'
 response_headers = [
 ,
 ))
 start_response
 return [response_body]
# 实例化WSGI server
httpd = make_server 
print 'end'

浏览器访问http://127.0.0.1:8051/,可以看到environment的内容。

另外,浏览器请求一次后,environment.py就结束了,程序在终端中输出内容如下:



可迭代的响应

如果把上面的可调用对象application的返回值:

return [response_body]

改成:

return response_body

这会导致WSGI程序的响应变慢。原因是字符串response_body也是可迭代的,它的每一次迭代只能得到1 byte的数据量,这也意味着每一次只向客户端发送1 byte的数据,直到发送完毕为止。所以,推荐使用return [response_body]。

如果可迭代响应含有多个字符串,那么Content-Length应该是这些字符串长度之和:

# ! /usr/bin/env python
# -*- coding: utf-8 -*- 
from wsgiref._______server import make_server
def application:
 response_body = [
 '%s: %s' %  for key, value in sorted)
 response_body = '
'.join
 response_body = [
 'The Beggining
',
 '*' * 30 + '
',
 response_body,
 '
' + '*' * 30 ,
 '
The End'
 # 求Content-Length
 content_length = sum for s in response_body])
 status = '200 OK'
 response_headers = [
 ,
 )
 start_response
 return response_body
httpd = make_server
httpd.handle_request
print 'end'

解析GET请求

运行environment.py,在浏览器中访问http://localhost:8051/ age=10&hobbies=software&hobbies=tunning,可以在响应的内容中找到:

QUERY_STRING: age=10&hobbies=software&hobbies=tunning
REQUEST_METHOD: GET

cgi.parse_qs函数可以很方便的处理QUERY_STRING,同时需要cgi.escape处理特殊字符以防止脚本注入,下面是个例子:

# ! /usr/bin/env python
# -*- coding: utf-8 -*- 
from cgi import parse_qs, escape
QUERY_STRING = 'age=10&hobbies=software&hobbies=tunning'
d = parse_qs
print d.get[0] # ['']是默认值,如果在QUERY_STRING中没找到age则返回默认值
print d.get
print d.get
print 10 * '*'
print escape; /script ')

输出如下:






然后,我们可以写一个基本的处理GET请求的动态网页了:

# ! /usr/bin/env python
# -*- coding: utf-8 -*- 
from wsgiref._______server import make_server
from cgi import parse_qs, escape
# html中form的method是get,action是当前页面
html = """
 html 
 body 
 form method="get" action="" 
 Age: input type="text" name="age" value="%s" 
 Hobbies:
 input
 name="hobbies" type="checkbox" value="software"
 %s
 Software
 input
 name="hobbies" type="checkbox" value="tunning"
 %s
 Auto Tunning
 input type="submit" value="Submit" 
 /form 
 Age: %s br 
 Hobbies: %s
 /body 
 /html 
def application :
 # 解析QUERY_STRING
 d = parse_qs
 age = d.get[0] # 返回age对应的值
 hobbies = d.get # 以list形式返回所有的hobbies
 # 防止脚本注入
 age = escape
 hobbies = [escape for hobby in hobbies]
 response_body = html % { 
 'checked-software': ['software' in hobbies],
 'checked-tunning': ['tunning' in hobbies],
 'age': age or 'Empty',
 'hobbies': ', '.join
 status = '200 OK'
 # 这次的content type是text/html
 response_headers = [
 ,
 ))
 start_response
 return [response_body]
httpd = make_server
# 能够一直处理请求
httpd.serve_forever
print 'end'

启动程序,在浏览器中访问http://localhost:8051/、http://localhost:8051/ age=10&hobbies=software&hobbies=tunning感受一下~

这个程序会一直运行,可以使用快捷键Ctrl-C终止它。

这段代码涉及两个我个人之前没用过的小技巧:

 "Age: %s" % {'age':12}
'Age: 12'
 hobbies = ['software']
 ['software' in hobbies]
'checked'
 ['tunning' in hobbies]
''

解析POST请求

对于POST请求,查询字符串是放在HTTP请求正文中的,而不是放在URL中。请求正文在environment字典变量中键wsgi.input对应的值中,这是一个类似file的变量,这个值是一个。The 指出,请求头中CONTENT_LENGTH字段表示正文的大小,但是可能为空、或者不存在,所以读取请求正文时候要用try/except。

下面是一个可以处理POST请求的动态网站:

# ! /usr/bin/env python
# -*- coding: utf-8 -*- 
from wsgiref._______server import make_server
from cgi import parse_qs, escape
# html中form的method是post
html = """
 html 
 body 
 form method="post" action="" 
 Age: input type="text" name="age" value="%s" 
 Hobbies:
 input
 name="hobbies" type="checkbox" value="software"
 %s
 Software
 input
 name="hobbies" type="checkbox" value="tunning"
 %s
 Auto Tunning
 input type="submit" value="Submit" 
 /form 
 Age: %s br 
 Hobbies: %s
 /body 
 /html 
def application:
 # CONTENT_LENGTH 可能为空,或者没有
 try:
 request_body_size = int)
 except :
 request_body_size = 0
 request_body = environ['wsgi.input'].read
 d = parse_qs
 # 获取数据
 age = d.get[0] 
 hobbies = d.get 
 # 转义,防止脚本注入
 age = escape
 hobbies = [escape for hobby in hobbies]
 response_body = html % { 
 'checked-software': ['software' in hobbies],
 'checked-tunning': ['tunning' in hobbies],
 'age': age or 'Empty',
 'hobbies': ', '.join
 status = '200 OK'
 response_headers = [
 ,
 ))
 start_response
 return [response_body]
httpd = make_server
httpd.serve_forever
print 'end' 

Python WSGI入门

这段内容参考自。

Web server

WSGI server就是一个web server,其处理一个HTTP请求的逻辑如下:

iterable = app
for data in iterable:
 # send data to client

app即WSGI application,environ即上文中的environment。可调用对象app返回一个可迭代的值,WSGI server获得这个值后将数据发送给客户端。

Web framework/app

即WSGI application。

中间件

中间件位于WSGI server和WSGI application之间,所以

一个示例

该示例中使用了中间件。

# ! /usr/bin/env python
# -*- coding: utf-8 -*- 
from wsgiref._______server import make_server
def application:
 response_body = 'hello world!'
 status = '200 OK'
 response_headers = [
 ,
 ))
 start_response
 return [response_body]
# 中间件
class Upperware:
 def __init__:
 self.wrapped_app = app
 def __call__:
 for data in self.wrapped_app:
 yield data.upper
wrapped_app = Upperware
httpd = make_server
httpd.serve_forever
print 'end'

然后

有了这些基础知识,就可以打造一个web框架了。感兴趣的话,可以阅读一下Bottle、Flask等的源码。

在还有更多关于WSGI的内容。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对萬仟网的支持。

Copyright © 2018 申博网址申博网址-申博官方网站下载 All Rights Reserved