python-为什么environ [‘wsgi.input’].read()会阻塞,即使PEP-3333允许也是如此?

问题

这是一个简单的WSGI应用程序,应该可以打印Content-Length
以及标头中的请求正文.

def application(environ, start_response):
    start_response('200 OK', [('Content-Type','text/plain')])
    content_length = int(environ['CONTENT_LENGTH'])
    print('---- Begin ----')
    print('CONTENT_LENGTH:', content_length)
    print('wsgi.input:', environ['wsgi.input'].read())
    print('---- End ----')
    return [b'Foo\n']

if __name__ == '__main__':
    from wsgiref import simple_server
    server = simple_server.make_server('0.0.0.0', 8080, application)
    server.serve_forever()

当我运行此应用程序时,它在以下调用中被阻塞:environ [‘wsgi.input’].read().

我使用Python 3解释器运行该应用程序,然后使用curl提交HTTP发布请求.

lone@debian:~$curl --data "a=1&b=2" http://localhost:8080/

curl命令被阻塞,等待输出. python解释器在environ [‘wsgi.input’].read()调用中被阻塞.

lone@debian:~$python3 foo.py
---- Begin ----
CONTENT_LENGTH: 7

从上面的输出中可以看到,在打印CONTENT_LENGTH之后,application()函数被阻塞了.

解决方法

我知道如何解决该问题:通过将Content-Length标头值传递给read()调用.

修改后的代码可解决此问题:

def application(environ, start_response):
    start_response('200 OK', [('Content-Type','text/plain')])
    content_length = int(environ['CONTENT_LENGTH'])
    print('---- Begin ----')
    print('CONTENT_LENGTH:', content_length)
    print('wsgi.input:', environ['wsgi.input'].read(content_length))
    print('---- End ----')
    return [b'Foo\n']

if __name__ == '__main__':
    from wsgiref import simple_server
    server = simple_server.make_server('0.0.0.0', 8080, application)
    server.serve_forever()

curl命令现在获取有效的HTTP响应.

lone@debian:~$curl --data "a=1&b=2" http://localhost:8080/
Foo
lone@debian:~$

application()函数还可以完成其执行.

lone@debian:~$python3 foo.py
---- Begin ----
CONTENT_LENGTH: 7
wsgi.input: b'a=1&b=2'
---- End ----
127.0.0.1 - - [06/Apr/2014 17:53:21] "POST / HTTP/1.1" 200 4

为什么在不带任何参数的情况下调用read时,environ [‘wsgi.input’].read()调用块为何?

PEP-3333文档似乎暗示它应该可以工作.这是相关的文本.

The server is not required to read past the client’s specified
Content-Length, and should simulate an end-of-file condition if
the application attempts to read past that point. The application
should not attempt to read more data than is specified by the CONTENT_LENGTH variable.

A server should allow read() to be called without an argument,
and return the remainder of the client’s input stream.

我了解,应用程序不应尝试读取超过CONTENT_LENGTH变量指定的更多数据.我不遵守该指令.但是服务器应允许在不带参数的情况下调用read(),并向我返回整个输入流.为什么不这样做呢?

最佳答案
因为它仅实现PEP 333,而不实现PEP 3333.

PEP 333没有通过返回空字符串来模拟流的结尾的条件.

在PEP 333中,如果WSGI服务器支持HTTP 1.1并且正在使用请求管道衬里(保持活动状态),并且尝试读取的内容超过CONTENT_LENGTH,则可能会遇到问题.

我建议您阅读PEP 333并将该语言与PEP 3333进行比较.

另请阅读:

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

我在其中描述了整个问题,因此在为Python 3更新PEP时做出了贡献.

转载注明原文:python-为什么environ [‘wsgi.input’].read()会阻塞,即使PEP-3333允许也是如此? - 代码日志