为什么Apache / WSGI将HEAD映射到GET?如何加快烧瓶头? [英] Why does Apache/WSGI map HEAD to GET? How to speed up HEAD in Flask?

查看:222
本文介绍了为什么Apache / WSGI将HEAD映射到GET?如何加快烧瓶头?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

下面是一个Flask应用程序,可以从命令行或通过Apache / WSGI运行:

  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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆