请查看底部的编辑以获取更多信息
我有两台服务器。两者都应该能够通过GET请求相互调用。为了发出请求(实际上,触发事件比发出请求更重要),我使用了以下代码:
function URLCallAsync($url, $params, $type='POST')
{
foreach ($params as $key => &$val) {
if (is_array($val)) $val = implode(',', $val);
$post_params[] = $key.'='.urlencode($val);
}
$post_string = implode('&', $post_params);
$parts=parse_url($url);
$fp = fsockopen($parts['host'],
isset($parts['port'])?$parts['port']:80,
$errno, $errstr, 30);
// Data goes in the path for a GET request
if('GET' == $type) $parts['path'] .= '?'.$post_string;
$out = "$type ".$parts['path']." HTTP/1.1'r'n";
$out.= "Host: ".$parts['host']."'r'n";
$out.= "Content-Type: application/x-www-form-urlencoded'r'n";
$out.= "Content-Length: ".strlen($post_string)."'r'n";
$out.= "Connection: Close'r'n'r'n";
// Data goes in the request body for a POST request
if ('POST' == $type && isset($post_string)) $out.= $post_string;
fwrite($fp, $out);
fclose($fp);
}
我在两台服务器上为函数提供了完全相同的数据(但url)(我复制了调用文件来测试它!!),但它只在一个方向上工作!
我把对该函数的调用写在日志文件中,这样我就可以调查是否出了问题。
服务器A->服务器B,工作正常,服务器A的日志文件包含正确的url
服务器B->服务器A,只在服务器B的日志文件中打印正确的信息,但服务器A从未收到请求。
发生这种事的原因是什么?
编辑:可能是不同种类的服务器吗?服务器A是nginx,服务器B是apache。服务器A的url中也有一个"~"符号,也许这就是问题所在?get请求的参数是用php的"urlencode"编码的,这可能会产生问题?
我试了一下,但问题仍然是请求没有通过服务器a。但从浏览器来看,它以某种方式运行得很好(假设我输入了带参数的正确URL)。
第2版:如果我用"file_get_contents"交换"URLCallAsync",它的工作原理应该是这样的。但问题是file_get_contents正在阻塞!所以它只能是函数本身。但奇怪的是,它的工作方向相反:(
第3版:函数"URLCallAsync"运行顺利,没有任何错误、通知或其他任何事情。只是其他服务器没有接收到它。file_get_contents到底有什么不同???
我让它工作起来了。
经过大量的wireshark操作,我发现file_get_contents甚至比我的异步函数更简单!
它只是完全省略了Content-Length字段!它只提供"GET…"answers"Host"。它也使用HTTP/1.0而不是1.1,但这并没有改变任何东西。
因此,解决方案是:同时发布Content-Length标头(由于我使用了GET,因此其值为0)将以某种方式使服务器拒绝请求。我不确定是服务器拒绝了请求,还是其他什么,比如防火墙可能检测到了"格式错误"的请求,但至少问题得到了解决。
因此,下次发送请求时,如果不需要,请不要提供Content-Length标头:)