【问题标题】:WP_REST_Response to download a fileWP_REST_Response 下载文件
【发布时间】:2017-11-15 09:12:50
【问题描述】:

是否可以在 WordPress 中使用 WP_REST_Response 返回文档(生成的 PDF、CSV)?

到目前为止,我一直在使用 register_rest_resource 注册自定义端点,但如果我尝试返回文件(例如,使用 PHP fpassthru($f)readfile($f) 我会收到“标头已发送”错误。

换句话说:如何使用 Wordpress REST API 返回文件?

感谢任何帮助!

谢谢

【问题讨论】:

  • “返回”给? API 返回 JSON。因此,如果您的问题基本上是“我可以将二进制数据放入 JSON 中吗”,那么答案是肯定的。你是否应该这样做或者在什么情况下它可能有意义,将是一个不同的问题。
  • 我同意 API 应该将 JSON 返回给 JS 被调用者。但是,如果我的 API 将(例如)订单 ID 作为输入并返回该订单发票的 PDF 文件,该怎么办?
  • 那么我会认为这是一个设计缺陷:p 大型二进制资产首先不应该通过这样的 API 传递。您的 API 应返回 PDF 的 URL,然后客户端可以使用该 URL 下载它。
  • 是的,但这需要两个调用:第一个调用生成 PDF 并将其保存在服务器磁盘上,第二个调用实际下载存储在磁盘上的 PDF。
  • 网址不必指向“静态”数据或文件。

标签: php wordpress rest wordpress-rest-api


【解决方案1】:

(我自己很快就需要这个,所以制定一个可能不完整的答案)

与 WP Media 核对后,我们收到了 .../?rest_route=/wp/v2/media/ID JSON API 回复,其中包含所要求的媒体文件的链接。

接下来,即source _url 的图像之一包含.../wp-content/uploads/2021/06/Screenshot-2021-06-18-at-10.25.05-150x150.png

按照 cmets(不流式传输二进制文件而是链接)将文件添加到 WP Media 集合,或者自定义端点可以响应链接到生成的和存储的文件的类似响应。

然后任何 JSON API 兼容的客户端都可以做需要的事情。在这种情况下生成一个下载链接。

【讨论】:

    【解决方案2】:

    您不能使用WP_REST_Response 来执行此操作。但是,可以使用 rest api 返回其他内容。

    如果您绝对确定您已准备好完整响应(包括标题,例如用于下载的Content-Disposition),您可以在生成最终响应后简单地exit;。请注意,这完全绕过了之后会调用的任何钩子,因此请谨慎使用。

    .csv 的示例

    $filename = 'example-file.csv';
    header("Access-Control-Expose-Headers: Content-Disposition", false);
    header('Content-type: text/csv');
    header("Content-Disposition: attachment; filename=\"$filename\"");
    
    // output starts here, do not add headers from this point on.
    $csv_file = fopen('php://output', 'w');
    
    $csv_header = array(
        'column-1',
        'column-2',
        'column-3',
    );
    
    fputcsv($csv_file, $csv_header);
    
    $data = array(
        array('a1', 'b1', 'c1'),
        array('a2', 'b2', 'c2'),
        array('a3', 'b3', 'c3'),
    );
    
    foreach ($data as $csv_data_entry) {
        fputcsv($csv_file, $csv_data_entry);
    }
    
    fclose($csv_file);
    
    // With a non-file request, you would usually return the result.
    // In this case, this would cause the "Headers already sent" errors, so an exit is required.
    exit;
    

    【讨论】:

      【解决方案3】:

      默认情况下,所有 REST 响应都通过 json_encode() 传递以返回 JSON 字符串。但是,REST 服务器提供了 WP 挂钩 rest_pre_serve_request,我们可以使用它来返回二进制数据。

      代码示例:

      <?php
      /**
       * Serves an image via the REST endpoint.
       *
       * By default, every REST response is passed through json_encode(), as the
       * typical REST response contains JSON data.
       *
       * This method hooks into the REST server to return a binary image.
       *
       * @param string $path Absolute path to the image to serve.
       * @param string $type The image mime type [png|jpg|gif]. Default is 'png'.
       *
       * @return WP_REST_Response The REST response object to serve an image.
       */
      function my_serve_image( $path, $type = 'png' ) {
          $response = new WP_REST_Response;
      
          if ( file_exists( $path ) ) {
              // Image exists, prepare a binary-data response.
              $response->set_data( file_get_contents( $path ) );
              $response->set_headers( [
                  'Content-Type'   => "image/$type",
                  'Content-Length' => filesize( $path ),
              ] );
      
              // HERE → This filter will return our binary image!
              add_filter( 'rest_pre_serve_request', 'my_do_serve_image', 0, 2 );
          } else {
              // Return a simple "not-found" JSON response.
              $response->set_data( 'not-found' );
              $response->set_status( 404 );
          }
      
          return $response;
      }
      
      /**
       * Action handler that is used by `serve_image()` to serve a binary image
       * instead of a JSON string.
       *
       * @return bool Returns true, if the image was served; this will skip the
       *              default REST response logic.
       */
      function my_do_serve_image( $served, $result ) {
          $is_image   = false;
          $image_data = null;
      
          // Check the "Content-Type" header to confirm that we really want to return
          // binary image data.
          foreach ( $result->get_headers() as $header => $value ) {
              if ( 'content-type' === strtolower( $header ) ) {
                  $is_image   = 0 === strpos( $value, 'image/' );
                  $image_data = $result->get_data();
                  break;
              }
          }
      
          // Output the binary data and tell the REST server to not send any other
          // details (via "return true").
          if ( $is_image && is_string( $image_data ) ) {
              echo $image_data;
      
              return true;
          }
      
          return $served;
      }
      

      示例用法:

      <?php
      // Register the REST endpoint.
      register_rest_route( 'my_sample/v1', 'image', [
          'method' => 'GET',
          'callback' => 'my_rest_get_image'
      ] );
      
      // Return the image data using our function above.
      function my_rest_get_image() {
          return my_serve_image( 'path/to/image.jpeg', 'jpg' );
      }
      

      【讨论】:

        猜你喜欢
        • 2018-10-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-04-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多