PHP,如何使用标头和正文重定向/转发HTTP请求?

2022-08-30 15:41:31

我有一个PHP页面,主.php它在服务器1上。

我在服务器2上有一个PHP页面主.php(相同的页面,不同的代码)。

main.php是一个 Web 服务。

我想将完整的HTTP请求转发到服务器1,转发到服务器2,这样当用户向main.php(服务器1)发送HTTP请求时,它将从服务器2上的main.php获得响应。

我希望对服务器 2 发出的请求与对服务器 1 的原始请求完全相同。

我通过以下方式获取 Http 请求数据:

$some_param  = $_REQUEST['param']
$body =file_get_contents('php://input');

让我们说我有

$server1_url = "11111";
$server2_url = "22222";

这样做的动机是,我有一个生产服务器和一个暂存服务器,我想将一些流量定向到新服务器以测试暂存服务器上的新功能。

如何重定向包含所有数据的请求或“克隆”完整请求,将其发送到新服务器并返回新响应?

感谢您的帮助!

p.s我尝试使用php curl,但我不明白它是如何工作的,我也找到了各种答案,但没有转发请求参数和正文。

再次感谢!


答案 1

如果您有权访问 Apache 服务器配置,则可以使用以下设置创建虚拟主机:

ProxyPreserveHost Off
ProxyPass / http://remotesite.domain.tld/
ProxyPassReverse / http://remotesite.domain.tld/
ProxyPassReverseCookieDomain remotesite.domain.tld proxysite.tld

您需要为此启用mod_proxy和mod_proxy_http。将 remotesite.domain.tld 替换为您转发到的站点,将 proxysite.tld 替换为转发器。

如果您无权访问服务器配置文件,您仍然可以在php中执行此操作,方法是手动设置curl并转发所有内容。

<?php

error_reporting(E_ALL);
ini_set('display_errors', '1');

/* Set it true for debugging. */
$logHeaders = FALSE;

/* Site to forward requests to.  */
$site = 'http://remotesite.domain.tld/';

/* Domains to use when rewriting some headers. */
$remoteDomain = 'remotesite.domain.tld';
$proxyDomain = 'proxysite.tld';

$request = $_SERVER['REQUEST_URI'];

$ch = curl_init();

/* If there was a POST request, then forward that as well.*/
if ($_SERVER['REQUEST_METHOD'] == 'POST')
{
    curl_setopt($ch, CURLOPT_POST, TRUE);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $_POST);
}
curl_setopt($ch, CURLOPT_URL, $site . $request);
curl_setopt($ch, CURLOPT_HEADER, TRUE);

$headers = getallheaders();

/* Translate some headers to make the remote party think we actually browsing that site. */
$extraHeaders = array();
if (isset($headers['Referer'])) 
{
    $extraHeaders[] = 'Referer: '. str_replace($proxyDomain, $remoteDomain, $headers['Referer']);
}
if (isset($headers['Origin'])) 
{
    $extraHeaders[] = 'Origin: '. str_replace($proxyDomain, $remoteDomain, $headers['Origin']);
}

/* Forward cookie as it came.  */
curl_setopt($ch, CURLOPT_HTTPHEADER, $extraHeaders);
if (isset($headers['Cookie']))
{
    curl_setopt($ch, CURLOPT_COOKIE, $headers['Cookie']);
}
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);

if ($logHeaders)
{
    $f = fopen("headers.txt", "a");
    curl_setopt($ch, CURLOPT_VERBOSE, TRUE);
    curl_setopt($ch, CURLOPT_STDERR, $f);
}

curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
$response = curl_exec($ch);

$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$headers = substr($response, 0, $header_size);
$body = substr($response, $header_size);

$headerArray = explode(PHP_EOL, $headers);

/* Process response headers. */
foreach($headerArray as $header)
{
    $colonPos = strpos($header, ':');
    if ($colonPos !== FALSE) 
    {
        $headerName = substr($header, 0, $colonPos);
        
        /* Ignore content headers, let the webserver decide how to deal with the content. */
        if (trim($headerName) == 'Content-Encoding') continue;
        if (trim($headerName) == 'Content-Length') continue;
        if (trim($headerName) == 'Transfer-Encoding') continue;
        if (trim($headerName) == 'Location') continue;
        /* -- */
        /* Change cookie domain for the proxy */
        if (trim($headerName) == 'Set-Cookie')
        {
            $header = str_replace('domain='.$remoteDomain, 'domain='.$proxyDomain, $header);
        }
        /* -- */
        
    }
    header($header, FALSE);
}

echo $body;

if ($logHeaders)
{
    fclose($f);
}
curl_close($ch);

?>

编辑:

当然,脚本必须位于(子)域的根目录中。你应该有一个.htaccess来重写所有内容:

RewriteEngine On
RewriteRule .* index.php

答案 2

这是我找到的解决方案(可能有更好的)

 public static function getResponse ($url,$headers,$body)
    {
        $params = '?' . http_build_query($headers);

        $redirect_url = $url . $params;

        $ch = curl_init($redirect_url);

        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
        curl_setopt($ch, CURLOPT_HEADER, 0);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        $response = curl_exec($ch);

        if (!isset($response))
            return null;
        return $response;
    }

推荐