【问题标题】:Downloading files in Mojolicious在 Mojolicious 中下载文件
【发布时间】:2014-12-30 22:51:45
【问题描述】:

简单的问题。我的 mojolicious 应用程序中生成了一个 .doc 文件。我想下载它。这是我的问题,我如何让浏览器下载它?

我正在使用 CPAN 模块 MsOffice::Word::HTML::Writer 来生成文档。

这是我的 mojolicious 应用程序中的子例程,它由 Jquery 中的 Ajax 请求调用:

sub down_doc {
  my $self = shift;

  my $doc = MsOffice::Word::HTML::Writer->new(
    title => "My new Doc",
    WordDocument => {View => 'Print'},
  );

  $doc->write("Content and Stuff");

  my $save = $doc->save_as("/docs/file.doc");

  $self->res->headers->content_disposition("attachment;filename=file.doc");
  $self->res->headers->content_type('application/msword');

  $self->render(data => $doc->content);
}

这是我在 Jquery 中的 Ajax 请求:

var request = $.ajax({
  url: "/down_doc",
  type: "post",
  data: {'data': data},
});

request.done(function(response, textStatus, jqXHR) {
  window.location.href = response;
});

我知道我的 Ajax“完成”处理程序是错误的,我只是在试验。如何让我的网页提示保存和下载 .doc 文件?

【问题讨论】:

    标签: javascript jquery ajax


    【解决方案1】:

    您的位置非常接近,但我会推荐以下任一选项...

    使用 Mojolicious 处理文件下载

    您可以安装插件Mojolicious::Plugin::RenderFile 来简化此操作。

    示例

    plugin 'RenderFile';
    
    sub down_doc {
      my $self = shift;
    
      my $doc = MsOffice::Word::HTML::Writer->new(
        title => "My new Doc",
        WordDocument => {View => 'Print'},
      );
    
      $doc->write("Content and Stuff");
      my $save = $doc->save_as("/docs/file.doc");    
      $self->render_file('filepath' => "/docs/file.doc");
    }
    

    或者,如果您只想使用 Mojo,以下方法将起作用,并在下面的链接中进一步说明。

    use Cwd;
    app->static->paths->[0] = getcwd;
    
    sub down_doc {
      my $self = shift;
    
      my $doc = MsOffice::Word::HTML::Writer->new(
        title => "My new Doc",
        WordDocument => {View => 'Print'},
      );
    
      $doc->write("Content and Stuff");
      my $save = $doc->save_as("/docs/file.doc");    
      shift->render_static("/docs/file.doc");
    }
    

    Reference

    【讨论】:

      【解决方案2】:

      这在服务器端确实不是问题,而是如果不使用(相对较新的)文件 API,您将无法保存来自 ajax 请求的响应。我建议用临时形式替换 ajax:

      $('<form method="post" action="/down_doc">') 
          .append( 
             $('<input type="hidden" name="data">')
                .attr("value", JSON.stringify(data))
          )
          .appendTo('body') 
          .submit();
      

      当表单提交并且您的 /down_doc 处理程序回复适当的 content-disposition 标头和文档数据时,浏览器将完成处理文件保存的工作。

      如果您不打算在请求后使用服务器上的文件,则可以删除此行:

      my $save = $doc->save_as("/docs/file.doc");
      

      【讨论】:

      • 我最终得到了这个工作,除了我还必须在那个临时表单上附加一个输入元素。 Mojolicious 不喜欢 data 属性,所以我的输入元素有需要作为其名称传递的数据。
      • 这么多? $('&lt;form method="post" action="/down_doc"&gt;') .append( $('&lt;input type="hidden" name="data"&gt;') .attr("value", JSON.stringify(data)) ) .appendTo('body') .submit();
      • 是的,差不多就是这样。我无法让“attr”Jquery 函数将数据作为 Mojolicious 可以检索的参数发送。我可能应该自己澄清一下。 var $input = $('&lt;input type="hidden" name="data"&gt;').val(data); $('&lt;form method="post" action="/make_doc"&gt;') .append($input) .appendTo('body') .submit(); }@Ben
      【解决方案3】:

      我尝试详细解释一下,如何将生成的文件内容作为字符串放入文件中。

      在 mojolicious 中,您在启动方法的主类中定义路由,例如我在 mojolicious 应用中所做的:

      # This method will run once at server start
        sub startup ($self) {
      # other code for startup
      # Normal route to controller
        $r->post('/export/chapter_doc')->to('Export#chapter_doc');
      }
      

      然后在“chaper_doc”方法中的导出控制器中,我执行了以下操作:

      sub chapter_doc($c)
      {
         # other code, for example to define $filename
         #force file download by setting a response header:
         $c->res->headers->content_disposition('attachment; filename='.$filename.'.doc;');
         $c->res->headers->content_type('application/doc');
         $doc_as_string = # HERE YOU CALL YOUR PerlModule that generates the content as string 
         return $req->render(msg => $doc_as_string);
      }
      

      在 mojolicious 中,模板文件位于模板文件夹中。模板文件名以 filename.html.ep 结尾就我而言,我得到了文件夹和文件结构:

      templates
      |_________export
                |_______chapter_doc.html.ep
      

      在模板 chapter_doc.html.ep 文件中我只放了:

      <%== $msg %>
      

      然后从我的应用程序中的任何其他模板中,我可以从如下形式调用路由:

         <form action="/export/chapter_doc" method="POST" type="multipart/form-data" style="float:right;">
           <input type="hidden" name="database" value="<%= $db %>">
           <input type="hidden" name="chapter" value="<%= $chapter %>">
          <button type="submit">doc export</button>
         </form>
      

      路由写在表单的action属性中。如果您想传输数据,请使用 POST 方法,否则使用 GET。

      当用户点击“文档导出”按钮时,浏览器不会显示新页面,而是停留在表单所在的当前页面上,并会自动开始下载生成的文件。

      这是我在 Firefox、Edge 和 Opera 中测试的。

      如果您有任何问题,请提出。然后我将进一步详细说明我的答案。

      【讨论】:

        猜你喜欢
        • 2013-01-15
        • 1970-01-01
        • 2011-06-16
        • 2017-08-25
        • 1970-01-01
        • 2014-05-11
        • 2011-03-31
        • 2021-12-20
        • 2012-04-23
        相关资源
        最近更新 更多