【问题标题】:How to return a file via Web Service如何通过 Web 服务返回文件
【发布时间】:2009-08-16 13:07:50
【问题描述】:

我正在开发一个 Web 服务,用户可以在其中输入参数并可以选择以各种文件格式(xml、html(在屏幕上)、csv 等)返回数据。

如果服务器生成文件内容(因此没有实际文件),则返回文件的 URL 不是一种选择。那么如何做到这一点呢?我知道有 xml 属性表明元素中的数据是二进制的,但这不会触发浏览器将数据下载为文件。

对于 XML/Web 服务,是否有类似 Content Disposition 的东西?

在一个非常相关的注释上:

javascript/AJAX 可以触发浏览器下载文件吗?我知道仅 js 无法“生成”文件(从某种意义上说,浏览器会将字符串下载为具有给定文件名的文件)但是如果 ajax 函数调用脚本并且脚本回复有标头设置为下载?

我将尝试最后一部分,但想知道是否已经有任何可靠的信息。


更多详情:

首先,感谢所有回复的人。所有的答案都非常有帮助和教育意义。

我想我可能会尝试对这种情况进行更多解释,以将所有跨越答案的 cmets/关注/建议联系起来。

我管理一个内部员工网站的项目。该项目主要处理进度查看和修改。至少有 4 个不同的 PHP 脚本查询 MySQL DB 以获取基本相同的数据。查询根据上下文略有不同。在一种情况下,它会提取按任务分组的每日时间表,在另一种情况下,它会查询整周的时间表并按人分组。在另一种情况下,它只查询一个人的每周日程安排。在某些情况下,它会输出数据,例如每人或每天或每个职位的小时总数,而在其他情况下,它只提供存储在数据库中的数据。

我开始对项目的某些方面感到内疚。显然,我可以将大量数据提取合并到一个包含的脚本中。我可能应该使用面向对象的 PHP 来处理结果。而且我更专注于让这个混乱的工作,而不是确保数据安全可靠,以及对数据库的压力最小化和优化。我什至不确定如何真正知道查询是否经过优化。

除了上面提到的内疚之外,我真的开始感到困惑了。在试图收拾东西的过程中,我发现自己陷入了一个结中,一个解决方案会搞砸一些工作正常的东西。

所以,我认为一个好的解决方案是创建一个 Web 服务,它可以简化整个过程并强制我对如何获取数据有一个逻辑(甚至是一个 API),并且对任何人都更有用当我最终不是首席开发人员时,谁试图接管。此外,对于站点后端的升级和转移(有一天它可能在使用 Cold Fusion 的 Windows 服务器上,但我一想到我不寒而栗),以及可能想要连接的其他软件,这将使整个事情更加便携与数据库。

但问题来了:

这个项目的整个起源是基于这样一个事实,即我们之前的调度解决方案是上传我们使用的非常昂贵的企业级调度软件生成的非常丑陋和非语义的 HTML 报告。对于这个可怕的 HTML 报告和生成它的软件,我们遇到的第一个问题是没有可以将 .ics "icalendar" 文件导入 Outlook 或 Google 日历的选项。我的个人使命是想办法将那些糟糕的报告转化为 ics 文件,从而开始我为什么开始学习 PHP、正则表达式和 MySQL。

所以,如果你还没有感到无聊和睡着,我认为 Web 服务是简化和简化日程安排过程的最佳选择,但如果我最终不得不使用普通的 PHP/MySQL 来获得最有价值的部分数据(日历文件)然后我倾向于放弃整个事情并继续解开结。

顺便说一句,我确实理解使用 Web 服务的脚本可以创建 ics 文件,并且当用户请求时可以简单地避免 AJAX。再次感谢所有让我更清楚这一点的人。我只是希望 Web 服务在其末端尽可能处理 DB 返回的所有内容,以便在 HTML/JS/PHP 和数据库之间有一个清晰的分区。

再次感谢!

【问题讨论】:

    标签: ajax web-services content-disposition


    【解决方案1】:

    要让浏览器下载文件,您可以这样做:

    window.location = "http://example.com/webservice-file-url";
    

    并使用标题:

    Content-Disposition: attachment; filename="filename.ext"
    

    如果您希望用户在屏幕上查看和下载之间进行选择,只需使用条件:

    if (requested_format == 'html') {
        //get an html version and show it on screen
        ajaxRequestForHTML();
    } else {
        //download the file
        window.location = "http://example.com/webservice-file-url";
    }
    

    【讨论】:

      【解决方案2】:

      恐怕这行不通。 AJAX 调用不会将其响应标头传递给浏览器。如果您更改标头,您唯一能做的就是您的 AJAX 调用可能会失败,因为标头将无法识别。

      我看到的唯一解决方案是将 URL 返回到文件并打开将触发下载的新 JS 窗口。

      【讨论】:

      • 好的,那么如果 Web 服务旨在从用户那里抽象出文件系统呢?脚本是否应该将文件的副本创建到用户可以访问的临时安全目录中,还是应该有处理文件请求的 mod_rewrite 规则?
      【解决方案3】:

      从 Web 服务返回一个字节数组。如果您想将文件发送到服务,也是如此。

      【讨论】:

      • 但不是所有从 Web 服务返回的数据都以 XML 形式返回吗? XML 包装器不会在下载时搞砸文件吗?
      • 取决于您未指定的 Web 服务的 type。我认为你的意思是 SOAP?如果是,那么让您的 JS 调用一个“页面”,该“页面”又调用该服务,在写入响应缓冲区之前设置适当的 mime 类型。很简单。
      • 抱歉,SOAP 是我唯一搞砸过的 WS 类型,所以我认为 XML 是 Web 服务与任何 ol 脚本不同的关键部分。
      • 大多数用于调用 Web 服务的代码都构建在一个框架上,该框架对您隐藏了 XML 包装器。此类代码将调用 Web 服务并接收字节数组,而不是 XML。如果您使用的是不隐藏 XML 的环境,那么,是的,您必须解析 XML。
      【解决方案4】:

      在典型的浏览器环境中,JavaScript 不能(出于安全原因)访问剪贴板或文件系统。有关讨论,请参阅 clipboard-image-directly-save-in-to-client-side-using-javascript 或 similar questions。

      也有例外,例如can-javascript-access-a-filesystem。

      【讨论】:

        【解决方案5】:

        Web 服务的意义在于它们并不意味着可以由浏览器直接访问 - 它们是供其他 Web 应用程序使用的 API。因此,您可能应该编写一个用户友好的前端,它调用 Web 服务并将数据作为 HTTP 响应中的文件提供。这将触发浏览器将其作为文件下载。

        【讨论】:

        • 所以这意味着浏览器(以及您建议的前端)似乎需要发挥更积极的作用。如果要返回的数据将在屏幕上显示,则该页面通过 AJAX 传递请求并返回响应(然后将其输出到屏幕)。但是如果要下载数据,请求会直接发送到服务器(通过表单操作)并因此返回 HTTP 响应,对吗?还是你说 AJAX 和 Web Services 不能混用?我不打算让 Web 服务直接与浏览器交互。但是在某些时候会建立连接,因此可能会涉及 AJAX。
        • AJAX 和 Web 服务可能可以混合使用,但我认为它们不应该是一种好的做法,因为 AJAX 不应该是用于直接调用Web服务。您可以有一个 CGI/PHP 脚本或一些直接从浏览器调用的脚本,然后调用 Web 服务并以正确的格式(文件、HTML 等)返回 HTTP 响应。因此,返回的 HTTP Content-Type 标头将指示浏览器下载(对于文件)或显示(对于 HTML)内容。希望这会有所帮助。
        • AJAX 常用于调用 Web 服务,可能返回 XML、JSON 甚至 HTML。
        • 我知道这是一个相当陈旧的线程,但我正在重新阅读它,并认为既然我已经有 2 年以上的经验,我会尝试重新表述我的初衷:目标是为所有服务器请求(或至少比简单表示更深入的所有服务器请求)拥有一个统一的 API。我仍然从根本上认为这是一个好主意,因为它简化了应用程序的几个方面,如验证、Web 服务等。但我现在也明白,通常 WS 的目标是公开应用程序的某些部分,而不仅仅是提供应用程序的替代(和冗余)抽象。干杯。
        【解决方案6】:

        您确定要将其设为 Web 服务吗?一个普通的网页怎么样,带有参数的表单字段,它只是将数据作为文件返回,并具有适当的内容处置?


        根据您的更新,我很确定您不希望 Web 服务返回 .ics 文件。您想要的是一个脚本,它将使用查询字符串接受一些参数,然后使用“附件”内容处置返回文件。这将提示用户打开 .ics 文件。

        现在,您还可以重构几个类似的脚本以减少冗余和维护。但是,我担心你所说的每一个改变都会破坏一些东西。在开始重构之前,您需要自己构建至少一个小型测试套件,最好是自动化的。这样,您将在每次小的更改后运行测试,看看您是否破坏了任何东西。这样一来,当你打破东西时,你只能打破一个小时的价值。

        我建议使用包含的脚本或 PHP 具有的任何重用机制来重构 PHP 脚本(我不知道 PHP)。然后您可能会发现一些通用代码将被适当地实现为 Web 服务。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2010-09-05
          • 1970-01-01
          • 1970-01-01
          • 2013-01-20
          • 2015-11-14
          • 2010-09-05
          • 1970-01-01
          • 2019-11-21
          相关资源
          最近更新 更多