为什么Apache / WSGI将HEAD映射到GET?如何加快烧瓶头? [英] Why does Apache/WSGI map HEAD to GET? How to speed up HEAD in Flask?
问题描述
import flask
app = flask.Flask(__ name__)
LENGTH = 1000000#one million
@ app.route('/',methods =''HEAD'])
def head():
return'x'* LENGTH#实际上并没有发送实体
@ app.route('/' ,方法= ['GET'])
def get():
import random
return''.join(str(random.randint(0,9))for x in range LENGTH))
if __name__ =='__main__':
app.run()#from命令行
else:
application = app#via Apache and WSGI
即使这个应用程序返回了一百万个随机数字。 GET请求需要花费很少的时间,但HEAD请求应该能够立即返回。这当然是一个说明性的例子。真正的应用程序会涉及对于GET请求产生较慢的较大的响应,但是也具有可以通过HEAD请求快速查询的预定大小。 (另一个场景:我试图将请求重定向到预先签名的Amazon S3 URL,对于HEAD和GET方法,必须以不同的方式签名。)
问题#1)当我从命令行运行Flask应用程序时,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请求。 b
$ b
我误解了什么?任何关于如何能够更快地处理HEAD请求的建议,最好不需要慢慢地生成一个只用于设置Content-Length头部的大型响应体?
要从Flask创建完整的响应,您需要执行下面的操作:
():
response = Response()
response.headers.add('content-length' ,LENGTH)
返回响应
这样会导致类似这样的结果:
连接到本地主机。
转义字符是'^]'。
HEAD / HTTP / 1.1
Host:localhost
HTTP / 1.0 200 OK
Content-Type:text / html; charset = utf-8
content-length:1000000
服务器:Werkzeug / 0.9.4 Python / 2.7.6
日期:2014年3月16日星期日22:59:16 GMT
这个测试只用标准的跑步者,并没有经过wsgi,但是没有什么区别。 / p>
对于强制使用get处理程序的Apache / WSGI,这个博客条目有一些提示,为什么发生这种情况。
见:烧瓶/ Werkzeug如何将HTTP内容长度标题附加到文件下载
Here's a Flask app that can be run either from the command-line or via 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
I.e., this app returns a million random digits. The GET request takes a non-trivial amount of time, but a HEAD request should be able to return almost immediately. This is of course an illustrative example; the real application would involve large responses that are slow to generate for a GET request, but that also have pre-determined size that could be quickly queried by a HEAD request. (Another scenario: I'm trying to redirect requests to pre-signed Amazon S3 URLs, which must be signed differently for HEAD and GET methods.)
Question #1) When I run the Flask app from the command-line, a HEAD request activates the head
function, as expected; but when I run this via Apache/WSGI, it activates the get
function. Why is this, and how can I work around it to get my desired behavior?
Question #2) instead of creating a dummy response (allocating a bunch of memory) for the HEAD request, why can't I return app.make_response('', 200, {'Content-Length':LENGTH})
?
My guess is that these are caused by a well-intentioned attempt to ensure that a HEAD request should always be consistent with the corresponding GET. So:
Guess #1) Either Apache or WSGI is internally rewriting HEAD to GET.
Guess #2) Flask doesn't trust me to set the Content-Length header manually, and rewrites it with the actual length of the response body... even for a HEAD request where this is in fact supposed to be empty.
Am I misunderstanding something? Any advice on how I can enable faster handling of HEAD requests, ideally without having to slowly generate a large response body that is only used to set the Content-Length header?
To create a complete response from Flask, you want to do something like this:
@app.route('/', methods=['HEAD'])
def head():
response = Response()
response.headers.add('content-length', LENGTH)
return response
That will then result in something like this:
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
This was tested with just the standard runner and not going through wsgi, but it shouldn't make a difference.
As for Apache/WSGI forcing the usage of the get handler, this blog entry has some hints as to why this is happening.
See: Flask/Werkzeug how to attach HTTP content-length header to file download
这篇关于为什么Apache / WSGI将HEAD映射到GET?如何加快烧瓶头?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!