【问题标题】:Forward BinaryFileResponse between two Symfony2 apps在两个 Symfony2 应用程序之间转发 BinaryFileResponse
【发布时间】:2016-07-20 10:23:11
【问题描述】:

我有两个 Symfony 应用程序 (API) 通过 HTTP 请求/响应使用 cURL PHP 函数相互通信。当他们收到小的 JSON 响应时,这很好用,但是在获取和提供文件时会出现问题。 API1(暴露在互联网上)需要提供一个只能由 API2(私有,通过 VPN 连接到 API1)访问的文件。

如果我在第一个 API 中对文件的内容进行编码,然后将其传递到响应正文中没有问题,我可以将文件重新转换回流并在第一个 API 中作为 BinaryFileResponse 提供。问题来自大文件 (>30MB),其中响应主体很大,symfony 无法分配那么多内存。

有没有办法将 BinaryFileResponse 从一个 API 转发或重定向到另一个 API,这样中间层对客户端是不可见的?

这是每个应用程序中的两段代码:

公共 API:

/**
 *
 * @Get("/api/login/getfile")
 */
public function testGetFilePrivate(Request $request)
{
    $url = 'private/variantset/9/getfile';
    $url = $this->container->getParameter('api2_url').$url;

    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
    curl_setopt($ch, CURLOPT_TIMEOUT_MS, 300000); //Set timeout in ms
    $response = curl_exec($ch);
    curl_close($ch);
    $data = json_decode($response, TRUE);
    $fileContent = base64_decode($data['filedata']);
    $response = new Response($fileContent);

    $disposition = $response->headers->makeDisposition(
        ResponseHeaderBag::DISPOSITION_ATTACHMENT,
        $data['filename']
    );

    $response->headers->set('Content-Disposition', $disposition);
    return $response;
}

私有 API:

/**
* @Get("/api/private/variantset/{id}/getfile")
*/
public function getVariantsetDataFileById($id)
{
    $variantset = $this->getVariantsetById($id);

    if(!$variantset){
        $response = array("getdata"=>"ko","error"=>"Variantset does not exists");        
        return new JsonResponse($response);
    }

    if($variantset->getCreated()){

        $auth_variants_dir = $this->container->getParameter('auth_variants_path');
        $file_path = $auth_variants_dir . '/' . $variantset->getDatafile() . '.gpg';

        $data = [
        "getdata"=>"ok",
        "filename" => $variantset->getDatafile() . '.gpg',
        "filedata" => base64_encode(file_get_contents($file_path))
        ];

        $response = new Response();
        $response->setContent($this->container->get('serializer')->serialize($data, 'json'));
        $response->headers->set('Content-Type', 'application/json');
    }else{
        $response = new JsonResponse(array("getdata"=>"ko","error"=>"Variantset does not have a file yet")); 
    }

    return $response;
}

【问题讨论】:

    标签: symfony curl download httprequest api-design


    【解决方案1】:

    通过结合中的答案终于找到了解决方案 Streaming a large file using PHPManipulate a string that is 30 million characters long

    不是使用 cURL PHP 函数,而是使用 HTTP 流包装器来捕获 API2 响应。这个包装器的输出然后使用 Symfony 的 StreamedResponse 类进行解析:

        $response = new StreamedResponse(function() use($url) {
            $handle = fopen($url, 'r');
            while (!feof($handle)) {
                $buffer = fread($handle, 1024);
                echo $buffer;
                flush();
            }
            fclose($handle);
        });
    
        $response->headers->set('Content-Type', 'application/octet-stream');
        return $response;
    

    我仍在为如何从初始请求中获取内容类型而苦苦挣扎,如果我最终设法正确获得它,我将编辑响应。欢迎提出任何建议。

    【讨论】:

      猜你喜欢
      • 2012-09-18
      • 1970-01-01
      • 1970-01-01
      • 2020-05-23
      • 2017-04-12
      • 1970-01-01
      • 1970-01-01
      • 2015-07-18
      • 1970-01-01
      相关资源
      最近更新 更多