这是一个Flask应用程序,可以从命令行或通过Apache / WSGI运行:
import flask
app = flask.Flask(__name__)
LENGTH = 1000000 # one million
@app.route('/', methods=['HEAD'])
def head():
return 'x' * LENGTH # response body isn't actually sent
@app.route('/', methods=['GET'])
def get():
import random
return ''.join(str(random.randint(0,9)) for x in range(LENGTH))
if __name__ == '__main__':
app.run() # from command-line
else:
application = app # via Apache and WSGI
即,这个应用程序返回一百万个随机数字. GET请求需要花费很多时间,但是HEAD请求应该能够立即返回.这当然是一个说明性的例子;实际应用程序将涉及对GET请求生成缓慢的大响应,但也具有可由HEAD请求快速查询的预定大小. (另一种情况:我正在尝试将请求重定向到预先签名的Amazon S3 URL,对于HEAD和GET方法,这些URL必须以不同方式签名.)
问题#1)当我从命令行运行Flask应用程序时,HEAD请求会按预期激活head函数;但是当我通过Apache / WSGI运行它时,它会激活get函数.为什么会这样,我如何解决它以获得我想要的行为?
问题#2)而不是为HEAD请求创建虚拟响应(分配一堆内存),为什么我不能返回app.make_response(”,200,{‘Content-Length’:LENGTH})?
我的猜测是,这些都是出于善意的尝试,以确保HEAD请求始终与相应的GET一致.所以:
猜猜#1)Apache或WSGI在内部重写HEAD到GET.
猜猜#2)Flask不相信我手动设置Content-Length标头,并用响应体的实际长度重写它……即使对于HEAD请求,其实际上应该是空的.
我误会了什么吗?关于如何能够更快地处理HEAD请求的任何建议,理想情况下无需缓慢生成仅用于设置Content-Length头的大响应体?
解决方法:
要从Flask创建完整的响应,您需要执行以下操作:
@app.route('/', methods=['HEAD'])
def head():
response = Response()
response.headers.add('content-length', LENGTH)
return response
那将导致类似这样的事情:
Connected to localhost.
Escape character is '^]'.
HEAD / HTTP/1.1
Host: localhost
HTTP/1.0 200 OK
Content-Type: text/html; charset=utf-8
content-length: 1000000
Server: Werkzeug/0.9.4 Python/2.7.6
Date: Sun, 16 Mar 2014 22:59:16 GMT
这只是用标准的跑步者测试而不是通过wsgi,但它不应该有所作为.
至于Apache / WSGI强制使用get处理程序,this blog entry提供了一些关于为什么会发生这种情况的提示.
见:Flask/Werkzeug how to attach HTTP content-length header to file download