使用 Python bottle 0.12.8 作为 Apache 服务器上 Windows 下的 CGI 应用程序的截断输出

Truncated output using Python bottle 0.12.8 as a CGI application under Windows on an Apache server

这是应用程序:

#!/home2/friendv0/Python-2.7.9/bin/python

from bottle import Bottle

app = Bottle()

@app.get('/')
def hello():
    return """<!DOCTYPE html>
<html lang="en">
<head>
<title>bottle Test</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="utf-8">
</head>
<body>
Hello!
</body>
</html>
"""

app.run(server='cgi')

结果输出为:

<!DOCTYPE html>
<html lang="en">
<head>
<title>bottle Test</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="utf-8">
</head>
<body>
Hello!
</body>

请注意,缺少结束标记 。这仅在应用程序 运行 作为 Windows 7(或 Windows 8)下的 CGI 脚本时发生——当它作为本机 WSGI 应用程序安装时不会发生。我在 Apache 2.2 和 Apache 2.4 上都试过了。请注意,当安装在 Linux 系统 运行ning Apache 2.2 上时,相同的 CGI 脚本 运行s without t运行cation。令人费解的是,我已经成功地 运行 其他 WSGI 应用程序作为 Windows 下的 CGI 脚本,而没有使用 bottle 使用的相同技术进行 t运行cation,即:

from wsgiref.handlers import CGIHandler
CGIHandler().run(application)

有没有其他人遇到过同样的问题?作为旁注:我对 运行ning bottle 作为 CGI 脚本感兴趣的原因是因为我的预期数量非常低,因此性能不会成为问题。但是在 Linux 服务器上(幸运的是,CGI 正在运行),我无法重新启动服务器,如果我必须对源代码进行紧急更改,我需要更改生效立即地。

嗯,我已经找到问题了。字符串文字长度为 201 个字符长(即 header 中的 content-length)。每行以单个 LF(换行)字符终止(即使在 Windows 上实际文本以 CRLF 终止)。然而,当文本被发送到浏览器时,每一行结尾现在都是一对 CR-LF,使得实际输出超过 201 个字符,但是由于 content-length 被设置在 header,有截断。我回到我的另一个正在工作的 WSGi-CGI 应用程序,现在记得因为在某些情况下我正在发送图像,所以我将 stdout 流设置为二进制模式(在 Unix/Linux 上没有必要)。如果我的模板开头没有它们,这显然会产生防止额外的回车 return 字符插入文本流的副作用。所以,现在我有以下代码:

import os
if os.name == 'nt':
    import msvcrt
    msvcrt.setmode(0, os.O_BINARY ) # 0 = sysin
    msvcrt.setmode(1, os.O_BINARY ) # 0 = stdout

app.run(server='cgi')

是的,我在我的 Flask 应用程序中遇到了同样的问题:Python 2.7.13 CGIHandler (mod_cgi),Windows 平台上的 Apache 2.2。
解决方案已确认!这是一个测试脚本:

#!C:/Python27/python.exe
# -*- coding: utf-8 -*-

import os

if os.name == 'nt':
    import msvcrt
    msvcrt.setmode( sys.stdin.fileno(), os.O_BINARY )
    msvcrt.setmode( sys.stdout.fileno(), os.O_BINARY )
    msvcrt.setmode( sys.stderr.fileno(), os.O_BINARY )

from wsgiref.handlers import CGIHandler

def application(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/plain')])
    return ['Hello World!\nXMX\nYMY\n']

if __name__ == '__main__':
    CGIHandler().run( application )

没有 msvcrt.setmode 输出将被截断。
使用 WSGI (mod_wsgi) 的同一个应用程序可以正常工作。
POSIX 系统上没有 CGI 问题。
另一种解决方案是将 Python 放在 'unbuffered mode' 中,在解释器指令中添加 -u 参数:

#!C:/Python27/python.exe -u
# -*- coding: utf-8 -*-

from wsgiref.handlers import CGIHandler

def application(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/plain')])
    return ['Hello World!\nXMX\nYMY\n']

if __name__ == '__main__':
    CGIHandler().run( application )

Python 文档参考说:

-u 强制标准输入、标准输出和标准错误完全无缓冲。在重要的系统上,还将 stdin、stdout 和 stderr 置于二进制模式。