【问题标题】:PHP, How to Redirect/Forward HTTP Request with header and body?PHP,如何使用标头和正文重定向/转发 HTTP 请求?
【发布时间】:2014-04-21 15:58:23
【问题描述】:

我有一个 PHP 页面 main.php,它位于服务器 1 上。

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

main.php 是一个 WebService。

我想将向服务器 1 发出的完整 HTTP 请求转发到服务器 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";

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

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

感谢您的帮助!

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

再次感谢!

【问题讨论】:

  • 代理和这个有什么关系?我也没有看到您引用的问题的任何适用答案,是吗?谢谢。
  • "将向服务器 1 发出的完整 http 请求转发到服务器 2"。那是一个代理。
  • 您是否需要 100% 在 php 中执行此操作?
  • @Marc B. 你是对的,对不起......我仍然找不到我可以使用的东西。

标签: php curl


【解决方案1】:

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

 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;
    }

【讨论】:

    【解决方案2】:

    如果您有权访问 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
    

    【讨论】:

    • 这对我不起作用。脚本转发到$site,而不是在URL中保留代理域。
    • 脚本运行良好。如果它对某人有帮助,那只是一件事。原始服务器正在将页面重定向到另一个,比如说从 http 到 https。由于脚本在通过 curl 获取内容后为内容设置标题,因此我不得不再添加一行以避免重定向循环。 if (trim($headerName) == 'Location') continue; 请检查您是否可以更新答案。谢谢。
    • 还有一点,要从另一台服务器获取数据,即使它重定向,我也必须使用curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); 来获取数据并显示。
    • 非常感谢。完美地工作。必须禁用 ssl 检查。
    • 我尝试将 xmlrpc GET 请求转发到支持 xmlrpc 的旧 joomla 1.5 站点。但是,尽管建议的代码成功完成(即我在 headers.txt 中看到 200 OK),但响应是:XML 错误:无效文档在第 1 行第 1 列结束。我将不胜感激有关如何解决错误的任何输入/想法.
    【解决方案3】:

    我使用了 Rehmat 和 Calmarius 的代码并进行了一些更改,所以现在它可以处理多个具有相同名称的字段,例如

    <input type="text" name="example[]">
    <input type="text" name="example[]">
    <input type="text" name="example[]">
    

    以及上传文件,包括使用相同字段名称的多个文件。

    这里是:

    <?php
    error_reporting(E_ALL);
    ini_set('display_errors', '1');
    
    class proxy {
        private $logHeaders     = false;
        
        /* Site to forward requests to.  */
        private $site           = 'http://redirectToSite';
        /* Domains to use when rewriting some headers. */
        private $remoteDomain   = 'redirectToSite';
        private $proxyDomain    = 'yourproxydomain.com';
    
        public function __construct() {
            $request = $_SERVER['REQUEST_URI'];
            $ch = curl_init();
    
            /* If there was a POST request, then forward that as well.*/
            if ($_SERVER['REQUEST_METHOD'] == 'POST') {
                $post   = $this->sanitizePostFields($_POST);
                $files  = $this->sanitizeFiles($_FILES);
                if ($files) {
                    $post = array_merge($post, $files);
                }
                
                curl_setopt($ch, CURLOPT_POST, TRUE);
                curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
                /*
                // this is enough if not uploading files
                curl_setopt(
                    $ch,
                    CURLOPT_POSTFIELDS,
                    http_build_query($_POST)
                );
                */
            }
            
            curl_setopt($ch, CURLOPT_URL, $this->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(
                    $this->proxyDomain,
                    $this->remoteDomain,
                    $headers['Referer']
                );
            }
            if (isset($headers['Origin'])) {
                $extraHeaders[] = 'Origin: '. str_replace(
                    $this->proxyDomain,
                    $this->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 ($this->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='.$this->remoteDomain,
                            'domain='.$this->proxyDomain,
                            $header
                        );
                    }
                    /* -- */
                    
                    if (trim($headerName) == 'Location') {
                        $header = str_replace(
                            $this->remoteDomain,
                            $this->proxyDomain,
                            $header
                        );
                    }
                }
                
                header($header, FALSE);
            }
    
            echo $body;
    
            if ($this->logHeaders) {
                fclose($f);
            }
            
            curl_close($ch);
        }
    
        private function sanitizePostFields($post, $fieldName = '') {
            if (empty($post)) { return false; }
            if (!is_array($post)) { return false; }
            
            $result = [];
            
            foreach ($post as $k => $v) {
                if (is_string($v)) {
                    $result[($fieldName ? "{$fieldName}[{$k}]" : $k)] = $v;
                }
                elseif (is_array($v)) {
                    $result = array_merge(
                        $result,
                        $this->sanitizePostFields($v, $k)
                    );
                }
            }
            
            return $result;
        }
    
        private function sanitizeFiles($files) {
            if (empty($files)) { return false; }
            if (!is_array($files)) { return false; }
            
            $result = [];
            
            foreach ($files as $k => $v) {
                if (empty($v['name'])) { continue; }
                
                if (is_array($v['name'])) {
                    // more than one file using the same name field[]
                    $nFields = count($v['name']);
                    for ($i = 0; $i < $nFields; $i++) {
                        if (empty($v['tmp_name'][$i])) { continue; }
                        $curl_file_upload = new CURLFile(
                            $v['tmp_name'][$i],
                            $v['type'][$i],
                            $v['name'][$i]
                        );
                        $result["{$k}[{$i}]"] = $curl_file_upload;
                    }
                }
                else {
                    $curl_file_upload = new CURLFile(
                        $v['tmp_name'],
                        $v['type'],
                        $v['name']
                    );
                    $result[$k] = $curl_file_upload;
                }
            }
            
            return $result;
        }
        
    }
    
    $proxy = new proxy();
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-11-09
      • 1970-01-01
      • 2017-03-29
      • 2018-07-19
      • 2010-12-30
      • 1970-01-01
      • 2012-03-13
      • 1970-01-01
      相关资源
      最近更新 更多