Apache 在响应 gzip 压缩请求时出现滞后

发布于 2024-08-07 08:26:40 字数 361 浏览 7 评论 0原文

对于我正在开发的应用程序,用户提交带有多部分表单数据(内容类型:multipart/form-data)的压缩 HTTP POST 请求(内容编码:GZIP)。我使用 mod_deflate 作为输入过滤器来解压缩,并通过 mod_wsgi 在 Django 中处理 Web 请求。

一般来说,一切都很好。但对于某些请求(确定性),从请求到响应几乎有一分钟的延迟。调查显示 django 中的处理立即完成,但服务器的响应停滞。如果请求未经过 GZIP 压缩,则一切正常。

请注意,为了处理 mod_wsgi 中的故障,我将 content-length 设置为未压缩的消息大小。

有人遇到过这个问题吗?有没有一种方法可以在 apache 处理响应时轻松调试它?

For an application I'm developing, the user submits a gzipped HTTP POST request (content-encoding: GZIP) with multipart form data (content-type: multipart/form-data). I use mod_deflate as an input filter to decompress and the web request is processed in Django via mod_wsgi.

Generally, everything is fine. But for certain requests (deterministic), there is almost a minute lag from request to response. Investigation shows that the processing in django is done immediately, but the response from the server stalls. If the request is not GZIPed, all works well.

Note that to deal with a glitch in mod_wsgi, I set content-length to the uncompressed mesage size.

Has anyone run into this problem? Is there a way to easily debug apache as it processes responses?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

別甾虛僞 2024-08-14 08:26:40

您认为 mod_wsgi 中存在什么故障?

事实很简单,WSGI 1.0 不支持改变请求内容的内容长度的变异输入过滤器。因此,从技术上讲,在使用 WSGI 1.0 时,您不能在 Apache 中使用 mod_deflate 来获取请求内容。将内容长度设置为实际大小以外的值很可能会堵塞 mod_deflate 的操作。

如果您希望能够处理压缩的请求内容,您需要超出 WSGI 1.0 规范并使用非标准代码。

我建议您阅读:

http: //blog.dscpl.com.au/2009/10/details-on-wsgi-10-amendmentsclarificat.html

这解释了这个问题以及有关它的建议。

我强烈建议您将此问题移至官方mod_wsgi 邮件列表进行讨论您需要如何编写代码。然而,如果您使用的是 Python 框架之一,您的操作可能会受到限制,因为它们将实现 WSGI 1.0,而您却无法执行此操作。


更新 1

从 mod_wsgi 列表的讨论来看,原始 WSGI 应用程序应该包装在以下 WSGI 中间件中。这仅适用于实际上提供空字符串作为输入结束标记的 WSGI 适配器,这是 WSGI 1.0 不需要的。这可能只适用于小型上传,因为所有内容都被读入内存。如果需要大量压缩上传,则应将累积的数据写出到文件中。

class Wrapper(object):

    def __init__(self, application):
        self.__application = application

    def __call__(self, environ, start_response):
        if environ.get('HTTP_CONTENT_ENCODING', '') == 'gzip':
            buffer = cStringIO.StringIO()
            input = environ['wsgi.input']
            blksize = 8192
            length = 0

            data = input.read(blksize)
            buffer.write(data)
            length += len(data)

            while data:
                data = input.read(blksize)
                buffer.write(data)
                length += len(data)

            buffer = cStringIO.StringIO(buffer.getvalue())

            environ['wsgi.input'] = buffer
            environ['CONTENT_LENGTH'] = length

        return self.__application(environ, start_response)


application = Wrapper(original_wsgi_application_callable)

What glitch do you believe exists in mod_wsgi?

The simple fact of the matter is that WSGI 1.0 doesn't support mutating input filters which change the content length of the request content. Thus technically you can't use mod_deflate in Apache for request content when using WSGI 1.0. Your setting the content length to be a value other than the actual size is most likely going to stuff up operation of mod_deflate.

If you want to be able to handle compressed request content you need to step outside of WSGI 1.0 specification and use non standard code.

I suggest you have a read of:

http://blog.dscpl.com.au/2009/10/details-on-wsgi-10-amendmentsclarificat.html

This explains this problem and the suggestions about it.

I'd very much suggest you take this issue over to the official mod_wsgi mailing list for discussion about how you need to write your code. If though you are using one of the Python frameworks however, you are probably going to be restricted in what you can do as they will implement WSGI 1.0 where you can't do this.


UPDATE 1

From discussion on mod_wsgi list, the original WSGI application should be wrapped in following WSGI middleware. This will only work on WSGI adapters that actually provide an empty string as end sentinel for input, something which WSGI 1.0 doesn't require. This should possibly only be used for small uploads as everything is read into memory. If need large compressed uploads, then data when accumulated should be written out to a file instead.

class Wrapper(object):

    def __init__(self, application):
        self.__application = application

    def __call__(self, environ, start_response):
        if environ.get('HTTP_CONTENT_ENCODING', '') == 'gzip':
            buffer = cStringIO.StringIO()
            input = environ['wsgi.input']
            blksize = 8192
            length = 0

            data = input.read(blksize)
            buffer.write(data)
            length += len(data)

            while data:
                data = input.read(blksize)
                buffer.write(data)
                length += len(data)

            buffer = cStringIO.StringIO(buffer.getvalue())

            environ['wsgi.input'] = buffer
            environ['CONTENT_LENGTH'] = length

        return self.__application(environ, start_response)


application = Wrapper(original_wsgi_application_callable)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文