字符串迭代导致WSGI响应变慢的真相
可迭代的, 这种响应。
[]
return [response_body]
改成:
return response_body
这会导致WSGI程序的响应速度减慢。原因是什么, 原因在于字符串是具备迭代能力的对象, 在对其进行迭操作时, 每一次迭代仅仅能够获得1字节大小的数据信息。
这种机制意味着, 程序会每次仅向客户端发送1字节大小的数据信息, 并需要持续进行这样的发送行为, 直到整个数据完全发送完毕为止。鉴于这一点, 业界倾向于推荐使用。
如果可迭代响应包含着多个字符串, 那么, 就应该把这些字符串的长度加在一起, 得出的总和就是最终的结果。
# !
/usr/bin/env python
# -*- coding: utf-8 -*-
from wsgiref.simple_server import make_server
def application(environ, start_response):
response_body = [
'%s: %s' % (key, value) for key, value in sorted(environ.items())
]
response_body = '\n'.join(response_body)
response_body = [
'The Beggining\n',
'*' * 30 + '\n',
response_body,
'\n' + '*' * 30 ,
'\nThe End'
]
# 求Content-Length
content_length = sum([len(s) for s in response_body])
status = '200 OK'
response_headers = [
('Content-Type', 'text/plain'),
('Content-Length', str(content_length))
]
start_response(status, response_headers)
return response_body
httpd = make_server('localhost', 8051, application)
httpd.handle_request()
print 'end'
对GET请求进行分析与解析。
当运行.py文件之后, 通过浏览器访问路径:8051/?age=10&=&=时, 能够在响应的内容里面去观察到这样的:
QUERY_STRING: age=10&hobbies=software&hobbies=tunning
REQUEST_METHOD: GET
通过调用 cgi.()函数, 能够对数据进行方便的处理。与此同时, 也必须让 cgi.()来处理一些特殊的字符, 这样才可以防止脚本注入的情况发生。下面提供的是一个具体的例子:
# !
/usr/bin/env python
# -*- coding: utf-8 -*-
from cgi import parse_qs, escape
QUERY_STRING = 'age=10&hobbies=software&hobbies=tunning'
d = parse_qs(QUERY_STRING)
print d.get('age', [''])[0] # ['']是默认值,如果在QUERY_STRING中没找到age则返回默认值
print d.get('hobbies', [])
print d.get('name', ['unknown'])
print 10 * '*'
print escape('')
输出如下:
10
'',''
''
**********

执行那个显示数字为一百二十三的弹窗命令。
接着, 我们能够编写一个可以处理GET请求的动态网页的这种基本的形式。
# !
/usr/bin/env python
# -*- coding: utf-8 -*-
from wsgiref.simple_server import make_server
from cgi import parse_qs, escape
# html中form的method是get,action是当前页面
html = """
Age:
Hobbies:
name="hobbies" type="checkbox" value="software"
%(checked-software)s
> Software
name="hobbies" type="checkbox" value="tunning"
%(checked-tunning)s
> Auto Tunning
Age: %(age)s
Hobbies: %(hobbies)s
""" def application (environ, start_response): # 解析QUERY_STRING d = parse_qs(environ['QUERY_STRING']) age = d.get('age', [''])[0] # 返回age对应的值 hobbies = d.get('hobbies', []) # 以list形式返回所有的hobbies # 防止脚本注入 age = escape(age) hobbies = [escape(hobby) for hobby in hobbies] response_body = html % { 'checked-software': ('', 'checked')['software' in hobbies], 'checked-tunning': ('', 'checked')['tunning' in hobbies], 'age': age or 'Empty', 'hobbies': ', '.join(hobbies or ['No Hobbies?']) } status = '200 OK' # 这次的content type是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) # 能够一直处理请求 httpd.serve_forever() print 'end'
你需要先启动相关程序工作, 然后打开浏览器, 尝试输入地址冒号, 接着是8051再跟着斜杠, 或者是冒号、8051、问号、age等于十, 之后再连着一个&符号跟一个等于号, 最后再加一个等于号及波浪号的组合页面链接, 以此来进行实际操作和体验。
这个程序会不间断地一直在运行当中, 你可以通过去使用快捷键那个Ctrl-C这个东西来进行终止它。
这段代码里面包含了两个小小的窍门, 而这两个小窍门是我个人在此之前从来没有使用或者说接触过过的。
>>> "Age: %(age)s" % {'age':12}
'Age: 12'
>>>
>>> hobbies = ['software']
>>> ('', 'checked')['software' in hobbies]
'checked'
>>> ('', 'checked')['tunning' in hobbies]
''
解析POST请求
针对那种POST类型的请求方式而言, 人们通常会发现查询字符串是位于HTTP请求的主体部分内部的, 它并不是被安置在网址里面的。
关于这个请求主体内容, 大家需要知道它是放在一个特定的字典变量里面的, 这个变量的钥匙是由wsgi.input这四个字母加上那个点构成的, 它所对应的值其实是一个能够像文件那样去读取东西的对象。
The指出, 请求头中存在某个字段, 这个字段是用来表示正文大小的, 但是这个字段可能是空的, 或者根本就不存在, 所以在读取请求正文的时候要用到try/。
下面展示的是一个动态性质的网站, 这个网站是可以对POST类型的数据提交请求进行具体处理的。
# !
/usr/bin/env python
# -*- coding: utf-8 -*-
from wsgiref.simple_server import make_server
from cgi import parse_qs, escape
# html中form的method是post
html = """
Age:
Hobbies:
name="hobbies" type="checkbox" value="software"
%(checked-software)s
> Software
name="hobbies" type="checkbox" value="tunning"
%(checked-tunning)s
> Auto Tunning
Age: %(age)s
Hobbies: %(hobbies)s
""" def application(environ, start_response): # CONTENT_LENGTH 可能为空,或者没有 try: request_body_size = int(environ.get('CONTENT_LENGTH', 0)) except (ValueError): request_body_size = 0 request_body = environ['wsgi.input'].read(request_body_size) d = parse_qs(request_body) # 获取数据 age = d.get('age', [''])[0] hobbies = d.get('hobbies', []) # 转义,防止脚本注入 age = escape(age) hobbies = [escape(hobby) for hobby in hobbies] response_body = html % { 'checked-software': ('', 'checked')['software' in hobbies], 'checked-tunning': ('', 'checked')['tunning' in hobbies], 'age': age or 'Empty', 'hobbies': ', '.join(hobbies or ['No 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() print 'end'
WSGI入门
这段内容参考自An to the Web (WSGI)。
Web

WSGI是一个web, 其处理一个HTTP请求的逻辑如下:
iterable = app(environ, start_response)
for data in iterable:
# send data to client
app就是WSGI, 就是上文所提到的内容。它作为一个可以调用的对象, 会返回一个可以进行迭代操作的值。然后, WSGI这个机制在获取到这个值之后, 就会把数据发送给客户端去处理。
Web /app
这就相当于WSGI。
中间件()
中间件是在WSGI与WSGI这两个东西之间, 所以。
这里有一个例子存在。
在这个示例里面, 人们使用了中间件这个技术。
# !
/usr/bin/env python
# -*- coding: utf-8 -*-
from wsgiref.simple_server import make_server
def application(environ, start_response):
response_body = 'hello world!
'
status = '200 OK'
response_headers = [
('Content-Type', 'text/plain'),
('Content-Length', str(len(response_body)))
]
start_response(status, response_headers)
return [response_body]
# 中间件
class Upperware:
def __init__(self, app):
self.wrapped_app = app
def __call__(self, environ, start_response):
for data in self.wrapped_app(environ, start_response):
yield data.upper()
wrapped_app = Upperware(application)
httpd = make_server('localhost', 8051, wrapped_app)
httpd.serve_forever()
print 'end'
然后
有了这些基础知识点之后, 接下来就可以去打造出一个web框架了。如果你对于这个内容感兴趣的话, 建议大家去阅读一下类似于Flask这样的源码内容。
要了解有关WSGI的更多信息, 可以参阅“了解关于WSGI”这一部分的内容。
总结
以上就是有关这篇完整文章里的全部内容了, 希望说出来的这篇内容能够对朋友们在进行学习或者是工作期间的状态起到一个有一定参考价值的作用。如果存在疑问的地方大家可以去留言交流一下, 谢谢各位朋友对于CSDN这个平台所给予的支持。
更多推荐


所有评论(0)