cURL 冻结 Apache 并在出现 404 错误时超时
cURL freeze Apache and time out on a 404 error
我遇到一个关于 cURL 请求的非常奇怪的问题。基本上,我有一些代码用于在 Symfony2 (http://symfonybricks.com/it/brick/wrap-legacy-php-code-by-a-symfony2-application) 上包装遗留 PHP 应用程序。它们是基本的 cURL 命令,应该拉取网页并显示它。但是,我注意到以下内容:
- 如果我对现有文件进行查询,它工作正常
- 如果我对不存在的文件进行查询,cURL 超时(因为我设置了 8 秒的超时),在此期间,它冻结了整个服务器,我不能从任何其他设备访问我的网站,直到它真正超时。
这是我的代码:
/**
* @Route("/", defaults={"controller" = "index.php", "controller2" = "", "controller3" = ""})
* @Route("/{controller}", defaults={"controller2" = "index.php", "controller3" = ""})
* @Route("/{controller}/", defaults={"controller2" = "index.php", "controller3" = ""})
* @Route("/{controller}/{controller2}", defaults={"controller3" = ""})
* @Route("/{controller}/{controller2}/", defaults={"controller3" = ""})
* @Route("/{controller}/{controller2}/{controller3}", defaults={"controller3" = "index.php"})
*/
public function getLegacyResourceAction($controller, $controller2, $controller3, Request $request)
{
$path_to_legacy_code = "http://XXX/";
$originalController = $request->getPathInfo();
$originalQueryString = $request->getQueryString();
$url = "{$path_to_legacy_code}{$originalController}?{$originalQueryString}";
//open connection
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_VERBOSE, 1);
curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']);
//Timeout
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 8);
curl_setopt($ch, CURLOPT_TIMEOUT, 8);
curl_setopt($ch, CURLOPT_MAXREDIRS, 5);
$stderr = fopen("{$this->container->getParameter('kernel.root_dir')}/logs/curl.txt", "a");
curl_setopt($ch, CURLOPT_STDERR, $stderr);
//echo "Login stuff in ".$this->container->getParameter('kernel.root_dir')."/logs/curl.txt";
curl_setopt($ch, CURLOPT_COOKIESESSION, 0);
curl_setopt($ch, CURLOPT_COOKIEFILE, 'cookies.txt');
curl_setopt($ch, CURLOPT_COOKIEJAR, 'cookies.txt');
$result = curl_exec($ch);
if (false === $result) {
echo curl_error($ch);
exit;
}
curl_close($ch);
fclose($stderr);
$Response = new Response($result);
return $Response;
这是我从有效响应中获得的日志:
* About to connect() to www.xxx.com port 80 (#0)
* Trying 178.32.223.113...
* connected
* Connected to www.xxx.com (178.32.223.113) port 80 (#0)
> GET /web/legacy/index.php HTTP/1.1
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:40.0) Gecko/20100101 Firefo$
Host: www.xxx.com
Accept: */*
Cookie: idto=116; PHPSESSID=a159rcjvh0fk6otukqqq9bkrd5
* additional stuff not fine transfer.c:1037: 0 0
* HTTP 1.1 or later with persistent connection, pipelining supported
< HTTP/1.1 200 OK
< Date: Sat, 05 Sep 2015 04:26:32 GMT
< Server: Apache/2.2.22 (Debian)
< X-Powered-By: PHP/5.5.28-1~dotdeb+7.1
< Expires: Thu, 19 Nov 1981 08:52:00 GMT
< Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
< Pragma: no-cache
< Vary: Accept-Encoding
< Transfer-Encoding: chunked
< Content-Type: text/html
<
* Connection #0 to host www.xxx.com left intact
* Closing connection #0
这是来自无效响应的代码:
* About to connect() to www.xxx.com port 80 (#0)
* Trying 178.32.223.113...
* connected
* Connected to www.xxx.com (178.32.223.113) port 80 (#0)
> GET /web/legacy/whatever.php HTTP/1.1
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:40.0) Gecko/20100101 Firefo$
Host: www.xxx.com
Accept: */*
Cookie: idto=116; PHPSESSID=a159rcjvh0fk6otukqqq9bkrd5
* additional stuff not fine transfer.c:1037: 0 0
* additional stuff not fine transfer.c:1037: 0 0
* additional stuff not fine transfer.c:1037: 0 0
* additional stuff not fine transfer.c:1037: 0 0
* additional stuff not fine transfer.c:1037: 0 0
* additional stuff not fine transfer.c:1037: 0 0
* additional stuff not fine transfer.c:1037: 0 0
* additional stuff not fine transfer.c:1037: 0 0
* additional stuff not fine transfer.c:1037: 0 0
* Operation timed out after 8001 milliseconds with 0 bytes received
* Closing connection #0
* About to connect() to www.xxx.com port 80 (#0)
* Trying 178.32.223.113...
* connected
* Connected to www.xxx.com (178.32.223.113) port 80 (#0)
> GET /web/legacy/legacy/whatever.php HTTP/1.1
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:40.0) Gecko/20100101 Firefo$
Host: www.xxx.com
Accept: */*
Cookie: idto=116; PHPSESSID=a159rcjvh0fk6otukqqq9bkrd5
* additional stuff not fine transfer.c:1037: 0 0
* additional stuff not fine transfer.c:1037: 0 0
* additional stuff not fine transfer.c:1037: 0 0
* additional stuff not fine transfer.c:1037: 0 0
* additional stuff not fine transfer.c:1037: 0 0
* additional stuff not fine transfer.c:1037: 0 0
* additional stuff not fine transfer.c:1037: 0 0
* additional stuff not fine transfer.c:1037: 0 0
* additional stuff not fine transfer.c:1037: 0 0
* Operation timed out after 8001 milliseconds with 0 bytes received
* Closing connection #0
* About to connect() to www.xxx.com port 80 (#0)
* Trying 178.32.223.113...
* connected
* Connected to www.xxx.com (178.32.223.113) port 80 (#0)
> GET /web/legacy/legacy/legacy/whatever.php HTTP/1.1
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:40.0) Gecko/20100101 Firefo$
Host: www.xxx.com
Accept: */*
下面的一切curl_exec($ch);直到超时才执行,没有给我机会检查 404 错误或其他东西。我已经找了好几天了,到目前为止还没有找到。
非常感谢!
编辑:
好的,所以我通过删除这一行解决了这个问题:
curl_setopt($ch, CURLOPT_COOKIEFILE, 'cookies.txt');
现在它给出了正确的 404 错误。我不知道为什么没有这条线它就可以工作。问题是,如果没有这一行,我将破坏遗留代码中的一些会话内容!
编辑 2:
我已经改变了:
- curl_setopt($ch, CURLOPT_COOKIESESSION, 0);
到
- curl_setopt($ch, CURLOPT_COOKIESESSION, 1);
现在它在 404 错误和我的会话中工作正常。我不知道为什么。
编辑 3:
好吧,我想我终于明白发生了什么事了:
- 在每个 cURL 请求中,它写入 cookie.txt 文件
- 如果有人查询 404 url,在超时之前,它会锁定 cookie.txt 文件,这就是为什么整个事情似乎都被冻结了。
据我所知,最好的解决方案是为每个用户生成一个不同的 cookie.txt 文件,以防止文件锁定。
我终于弄清楚了,原来我遇到了两个问题:
- 没有配置超时,所以如果我尝试查询一个不存在的网页,它将无限循环。
- 我为每个人使用相同的 cookie 文件,如果有人陷入前面提到的这种循环,它会文件锁定 cookie 文件,阻止其他用户访问该站点。
我遇到一个关于 cURL 请求的非常奇怪的问题。基本上,我有一些代码用于在 Symfony2 (http://symfonybricks.com/it/brick/wrap-legacy-php-code-by-a-symfony2-application) 上包装遗留 PHP 应用程序。它们是基本的 cURL 命令,应该拉取网页并显示它。但是,我注意到以下内容:
- 如果我对现有文件进行查询,它工作正常
- 如果我对不存在的文件进行查询,cURL 超时(因为我设置了 8 秒的超时),在此期间,它冻结了整个服务器,我不能从任何其他设备访问我的网站,直到它真正超时。
这是我的代码:
/**
* @Route("/", defaults={"controller" = "index.php", "controller2" = "", "controller3" = ""})
* @Route("/{controller}", defaults={"controller2" = "index.php", "controller3" = ""})
* @Route("/{controller}/", defaults={"controller2" = "index.php", "controller3" = ""})
* @Route("/{controller}/{controller2}", defaults={"controller3" = ""})
* @Route("/{controller}/{controller2}/", defaults={"controller3" = ""})
* @Route("/{controller}/{controller2}/{controller3}", defaults={"controller3" = "index.php"})
*/
public function getLegacyResourceAction($controller, $controller2, $controller3, Request $request)
{
$path_to_legacy_code = "http://XXX/";
$originalController = $request->getPathInfo();
$originalQueryString = $request->getQueryString();
$url = "{$path_to_legacy_code}{$originalController}?{$originalQueryString}";
//open connection
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_VERBOSE, 1);
curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']);
//Timeout
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 8);
curl_setopt($ch, CURLOPT_TIMEOUT, 8);
curl_setopt($ch, CURLOPT_MAXREDIRS, 5);
$stderr = fopen("{$this->container->getParameter('kernel.root_dir')}/logs/curl.txt", "a");
curl_setopt($ch, CURLOPT_STDERR, $stderr);
//echo "Login stuff in ".$this->container->getParameter('kernel.root_dir')."/logs/curl.txt";
curl_setopt($ch, CURLOPT_COOKIESESSION, 0);
curl_setopt($ch, CURLOPT_COOKIEFILE, 'cookies.txt');
curl_setopt($ch, CURLOPT_COOKIEJAR, 'cookies.txt');
$result = curl_exec($ch);
if (false === $result) {
echo curl_error($ch);
exit;
}
curl_close($ch);
fclose($stderr);
$Response = new Response($result);
return $Response;
这是我从有效响应中获得的日志:
* About to connect() to www.xxx.com port 80 (#0)
* Trying 178.32.223.113...
* connected
* Connected to www.xxx.com (178.32.223.113) port 80 (#0)
> GET /web/legacy/index.php HTTP/1.1
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:40.0) Gecko/20100101 Firefo$
Host: www.xxx.com
Accept: */*
Cookie: idto=116; PHPSESSID=a159rcjvh0fk6otukqqq9bkrd5
* additional stuff not fine transfer.c:1037: 0 0
* HTTP 1.1 or later with persistent connection, pipelining supported
< HTTP/1.1 200 OK
< Date: Sat, 05 Sep 2015 04:26:32 GMT
< Server: Apache/2.2.22 (Debian)
< X-Powered-By: PHP/5.5.28-1~dotdeb+7.1
< Expires: Thu, 19 Nov 1981 08:52:00 GMT
< Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
< Pragma: no-cache
< Vary: Accept-Encoding
< Transfer-Encoding: chunked
< Content-Type: text/html
<
* Connection #0 to host www.xxx.com left intact
* Closing connection #0
这是来自无效响应的代码:
* About to connect() to www.xxx.com port 80 (#0)
* Trying 178.32.223.113...
* connected
* Connected to www.xxx.com (178.32.223.113) port 80 (#0)
> GET /web/legacy/whatever.php HTTP/1.1
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:40.0) Gecko/20100101 Firefo$
Host: www.xxx.com
Accept: */*
Cookie: idto=116; PHPSESSID=a159rcjvh0fk6otukqqq9bkrd5
* additional stuff not fine transfer.c:1037: 0 0
* additional stuff not fine transfer.c:1037: 0 0
* additional stuff not fine transfer.c:1037: 0 0
* additional stuff not fine transfer.c:1037: 0 0
* additional stuff not fine transfer.c:1037: 0 0
* additional stuff not fine transfer.c:1037: 0 0
* additional stuff not fine transfer.c:1037: 0 0
* additional stuff not fine transfer.c:1037: 0 0
* additional stuff not fine transfer.c:1037: 0 0
* Operation timed out after 8001 milliseconds with 0 bytes received
* Closing connection #0
* About to connect() to www.xxx.com port 80 (#0)
* Trying 178.32.223.113...
* connected
* Connected to www.xxx.com (178.32.223.113) port 80 (#0)
> GET /web/legacy/legacy/whatever.php HTTP/1.1
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:40.0) Gecko/20100101 Firefo$
Host: www.xxx.com
Accept: */*
Cookie: idto=116; PHPSESSID=a159rcjvh0fk6otukqqq9bkrd5
* additional stuff not fine transfer.c:1037: 0 0
* additional stuff not fine transfer.c:1037: 0 0
* additional stuff not fine transfer.c:1037: 0 0
* additional stuff not fine transfer.c:1037: 0 0
* additional stuff not fine transfer.c:1037: 0 0
* additional stuff not fine transfer.c:1037: 0 0
* additional stuff not fine transfer.c:1037: 0 0
* additional stuff not fine transfer.c:1037: 0 0
* additional stuff not fine transfer.c:1037: 0 0
* Operation timed out after 8001 milliseconds with 0 bytes received
* Closing connection #0
* About to connect() to www.xxx.com port 80 (#0)
* Trying 178.32.223.113...
* connected
* Connected to www.xxx.com (178.32.223.113) port 80 (#0)
> GET /web/legacy/legacy/legacy/whatever.php HTTP/1.1
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:40.0) Gecko/20100101 Firefo$
Host: www.xxx.com
Accept: */*
下面的一切curl_exec($ch);直到超时才执行,没有给我机会检查 404 错误或其他东西。我已经找了好几天了,到目前为止还没有找到。
非常感谢!
编辑:
好的,所以我通过删除这一行解决了这个问题:
curl_setopt($ch, CURLOPT_COOKIEFILE, 'cookies.txt');
现在它给出了正确的 404 错误。我不知道为什么没有这条线它就可以工作。问题是,如果没有这一行,我将破坏遗留代码中的一些会话内容!
编辑 2:
我已经改变了:
- curl_setopt($ch, CURLOPT_COOKIESESSION, 0);
到
- curl_setopt($ch, CURLOPT_COOKIESESSION, 1);
现在它在 404 错误和我的会话中工作正常。我不知道为什么。
编辑 3:
好吧,我想我终于明白发生了什么事了:
- 在每个 cURL 请求中,它写入 cookie.txt 文件
- 如果有人查询 404 url,在超时之前,它会锁定 cookie.txt 文件,这就是为什么整个事情似乎都被冻结了。
据我所知,最好的解决方案是为每个用户生成一个不同的 cookie.txt 文件,以防止文件锁定。
我终于弄清楚了,原来我遇到了两个问题:
- 没有配置超时,所以如果我尝试查询一个不存在的网页,它将无限循环。
- 我为每个人使用相同的 cookie 文件,如果有人陷入前面提到的这种循环,它会文件锁定 cookie 文件,阻止其他用户访问该站点。