Python CGI将正确的文本返回到curl,但浏览器显示尾随零

Python CGI将正确的文本返回到curl,但浏览器显示尾随零,python,apache,curl,cgi,Python,Apache,Curl,Cgi,我用Python 3编写了这个简单的CGI应用程序: #! /usr/bin/env python3.4 print("Content-type: text/html\n") print("AAAA") 如果我使用任何浏览器访问URL,我会看到一个页面显示:“AAAA 0”。它在Firefox、Chrome和Mac上的Safari以及iPhone上的Safari中都能准确地显示这一点。将“AAAA”更改为任何其他值都会相应地更改所有浏览器中的输出,但尾随的“0”始终保留在每个浏览器中 浏

我用Python 3编写了这个简单的CGI应用程序:

#! /usr/bin/env python3.4

print("Content-type: text/html\n")

print("AAAA")
  • 如果我使用任何浏览器访问URL,我会看到一个页面显示:“AAAA 0”。它在Firefox、Chrome和Mac上的Safari以及iPhone上的Safari中都能准确地显示这一点。将“AAAA”更改为任何其他值都会相应地更改所有浏览器中的输出,但尾随的“0”始终保留在每个浏览器中

  • 浏览器的“视图源”始终显示预期的字符串+换行符(当然,浏览器将其视为空格),后跟意外的0:

    AAAA
    0
    
  • 直接从服务器的命令行(./foo.py | hex)执行它,并使用十六进制编辑器查看输出,生成预期的输出:标题行和内容行,内容行为41 0A(“AAAA\n”)

  • 从我的Mac笔记本电脑和Linux服务器的命令行使用curl同样会产生我期望的十六进制输出:41 0A

  • 任何(测试)平台上的旋度均不显示尾随零。所有平台上的所有浏览器都会显示尾随的零

  • 如果我删除了第二条“print”语句,只为标题保留了一条“print”语句,则所有浏览器中的尾随“0”都会消失,只留下一个空白页,但是如果我在标题打印之后放置任何print语句,则所有浏览器中都会出现尾随的零,但不会出现在任何浏览器中。即使是一个空的“print()”也会在“view source”的第二行生成一个空的第一行(我相信是换行符),后跟一个“0”。如果我添加更多的打印行,插入正确的doctype&html,则在源代码中的end-html标记后会显示尾随的零。如果打印除标题以外的任何内容,浏览器源中将显示一个尾随的零

  • 更改为Python3.2没有任何区别

  • 因此,为了使curl-spoof成为一个浏览器,我从几个浏览器中添加了“用户代理”。没有区别。Curl仍然始终显示我期望它显示的内容,并且所有浏览器仍然显示一个尾随的零

  • 重新键入简单代码(不是复制和粘贴)以确保没有不可见的字符会产生相同的结果(Python源代码的十六进制视图、在服务器上运行的输出以及curl获得的输出都不会显示额外的字符)

  • 这是使用Apache+CGI共享主机,我没有更改任何Apache文件或创建任何.htaccess文件

  • 我可以使用mod_wsgi,它可以很好地工作,如果这是为了生产,但它是为了学习。我试图教孩子们如何使用低级CGI,让他们手动从ENV变量中提取GET数据,等等,这样他们可以在升级到更多的预构建功能(CGI模块,然后是WSGI,然后是Flask,等等)之前看到下面发生了什么。重点是要理解发生了什么,但我没有

那么,有谁能告诉我在这个最基本的网络应用程序中发生了什么?“0”来自哪里(成功状态代码?),为什么它显示在浏览器源代码中而不显示在curl中?最重要的是,我如何摆脱它

更新: 只有当我的浏览器在使用ATT的“LTE”进行数据传输的手机上,或者任何浏览器通过连接到ATT的“LTE”访问Web时,才会出现此问题。如果我把手机带进房间,它会切换到Comcast/Wifi,刷新浏览器页面,“AAAA 0”会变成“AAAA”。走出家门(超出wifi范围),使用LTE刷新,然后“AAAA”变回“AAAA 0”。笔记本电脑上的浏览器也是如此

因此,这里是连接笔记本电脑并在所有浏览器中显示“AAAA 0”时的telnet输出(我看不出有问题,就像在curl中一样):


尾随的“0”可能来自分块响应格式,但浏览器不应显示它

如果您为响应添加了一个大小正确的“Content-Length”头,那么就应该取消它的权限,因为Apache不会使用分块响应,因为只有在长度未知的情况下才会使用分块响应

如果您使用“telnet”连接到服务器并手动发出请求,您将获得什么样的完整输出

telnet server-hostname 80
然后输入:

GET /some/url HTTP/1.0
Host: virtual-hostname

之后有一个额外的空行。

只是为了踢,在脚本末尾抛出一个
sys.exit(1)
。查看是否打印了1。嘿,这是一个很好的猜测,但是,不,在sys.exit(1)作为最后一行时,它在浏览器中仍然显示尾随零,在curl中没有尾随任何内容。请尝试运行
curl--忽略内容长度
。当您这样做时,
0
是否显示?您的apache是否在chroot监狱中运行?如果是这样的话,您能在chroot内部手动运行CGI脚本吗?尝试编写一个简单的sh CGI:
#/bin/sh
/
echo“内容类型:text/html”
/
echo”“
/
echo“AAAA”
。CGI的行为如何?当我这样做时,它会在nginx的503页上显示一个错误,说明该网站尚未建立。共享主机来自Web派系,如果我没记错的话,他们前面有一个nginx服务器,它将直接为静态.html页面提供服务,或者将动态页面转发给Apache实例,例如CGI调用或(您出色的)mod_wsgi。上面的telnet命令显然没有通过nginx,即使我请求静态主页。正如你所猜测的,问题消失了。必须这样做很烦人,因为我们不能简单地边打印边打印,而是必须生成输出,连接它,测量它,然后输出标题,但是我们要用mod_wsgi实现这一点,所以哦,好吧。我仍然想知道到底发生了什么,为什么它会出现在所有浏览器中,而不是在curl中。你能在你的问题中添加你从telnet测试中获得的完整输出,而不包含内容长度吗。然后我也许可以明白为什么。Graham,正如我上面所说的,您的telnet测试永远不会到达Apache。相反,nginx返回相同的超长pla
GET /some/url HTTP/1.0
Host: virtual-hostname