我在Linux服务器上运行Apache(2.2.14)上的PHP(PHP 5.3.2)应用程序。在其历史记录中,用户开始在其浏览器中看到以下消息:“请求实体太大”。 首次谷歌搜索建议,当上传的文件太大或者cookie过大时,就会发生这种情况。但它不会在文件上传时发生,仅在登录时始终在登录页面上发生。用户只需通过页面上的普通POST表单进入此页面。并且cookie仅包含会话ID。
此外,apache正在记录“Invalid Content-Length”。这是在我的任何代码执行之前记录的。尽管$ _POST应该包含一些数据,但它是空的。当我添加以下行时:
error_log("Content-Length: ".$_SERVER['CONTENT_LENGTH']);
它说
Content-Length: 32, 32
这似乎确实无效。更改浏览器或重置用户PC似乎没有帮助。一切都在第二天开始工作。
问题出在哪里?是Apache,PHP,用户的网络设置吗?如果我需要添加更多信息,请告诉我。
答案 0 :(得分:5)
在过去的几天里,我们遇到了Apache在error_log中记录的“Invalid Content-Length”消息。 仅从几个特定的IP类跟踪了一些访问者的问题,例如Movistar Argentina:200.81.44.201 使用tcpdump / whireshark进一步检查请求时,我们发现POST请求包含一些
重复标题,即Content-Length和Content-Type
真正的问题在于Content-Length,因为Apache通过连接来处理多个变量,例如:
Content-Length: 51
Content-Length: 51
结果将是:
Content-Length: 51, 51
然后Apache尝试将字符串“51,51”转换为不可能的整数。 在较新的Apache> 2.2.17,或者使用反向移植的补丁Apache记录错误:413请求实体太大,使用较旧的Apache,进程只是挂起消耗大量的CPU时间。 在IP类后面,我们看到更多不同的客户端,因此可能是错误配置的3G网关代理服务器,因为它们会复制这些标头。 因此,我们找到了一个解决方案,将Apache配置为仅使用一个Content-Length和一个Content-Type Headers重写Request: 这是我的代码,使用mod_headers和在httpd.conf中插入的SetEnvIfNoCase:
SetEnvIfNoCase Content-Length (.*), MyContentLength=$1
SetEnvIfNoCase Content-Type (.*), MyContentType=$1
RequestHeader set Content-Length: "%{MyContentLength}e" env=MyContentLength
RequestHeader set Content-Type: "%{MyContentType}e" env=MyContentType
您可以自由测试并使用此代码,以过滤掉重复的Content-Length HTTP Header变量。
答案 1 :(得分:2)
调查此类问题的最简单方法是使用TCPDump将客户端和服务器之间发送的数据包捕获到文件中,然后使用Wireshark将数据包视为TCP流。
捕获数据包的命令示例是。
tcpdump -vvv -A -i eth0'host 123.123.10.12&&端口80'-w eth0.dat
因为它是您的登录页面,您可能需要解码TCP流,因为它应该在HTTPS后面 - 这可以使用http://segfault.in/2010/11/decrypt-https-traffic-using-wireshark-and-key-file/
中的说明来完成质粒87几乎肯定是正确的 - 听起来其中一个标题正在大量增长并最终变得比Apache LimitRequestFieldSize更大。
只要它缓慢增长而不是一次性增长,你可以通过检查全局变量来调查它。
function checkVars(){
$varsToCheck = array($GLOBALS, $_SERVER, $_GET, $_POST, $_FILES, $_REQUEST, $_SESSION, $_ENV, $_COOKIE);
foreach($varToCheck as $var){
foreach($var as $key => $value){
if(count($key) > 1024){
logToFile("Found ridiculous key: ".$key." value is ".$value);
}
if(count($value) > 1024){
logToFile("Found ridiculous value for key: ".$key." value is ".$value);
}
}
}
}