2

我正在开发一个应用程序,它为用户提供一些下载文件的链接。该页面本身由 MVC 控制器提供,但链接指向在单独域上运行的 WebAPI 控制器。

(我更喜欢同一个域,但由于各种原因,它必须是一个单独的项目,它将在一个单独的域上运行。我不认为 CORS 是问题的一部分,因为这不使用 XHR,但我提到了它以防万一)。

所以在开发中,主要的MVC项目是http://localhost:56626/Reports/

页面上的链接可能如下所示:

<a href="http://localhost:51288/ReportDownload?ID=12345">Report 12345</a>

其中端口 51288 托管 Web API。

WebAPI 控制器使用 ReportID 定位文件,并将其内容写入响应流,将处置设置为附件:

//security.permission  checks and scaffolding/database interaction
//left out for clarity
 try
 {
    string filename = @"C:\ReportFiles\TestReport.csv";
    var stream = new FileStream(path, FileMode.Open);
    result.Content = new StreamContent(stream);
    result.Content.Headers.ContentType = new MediaTypeHeaderValue("text/csv");
    var disp = new ContentDispositionHeaderValue("attachment");
    disp.FileName = "TestReport.csv";
    result.Content.Headers.ContentDisposition = disp;
    return result;
}
catch(Exception ex)
{
   //how to return a response that won't redirect on error?
}

通过这样做,用户可以单击链接,无需任何重定向,系统会提示用户保存或打开文件,这正是我想要的;他们留在带有链接的原始页面上,只是从浏览器中获得一个打开/保存对话框。

当 Web API 控制器出现问题时,就会出现问题 - 异常或某些内部逻辑条件意味着无法下载文件。

  • 在这种情况下,当单击链接时,不会发生下载(显然),而是将它们带到目标 URL,即http://localhost:51288/api/ReportDownload?ReportID=12345这不符合我的要求。

  • 我更希望能够通过在响应中返回例如 HTTP 500 以某种方式在客户端捕获错误,并向用户显示下载失败的消息。

现在说实话,我什至不明白浏览器如何首先执行“就地”文件/保存对话框:

  • 我一直认为,如果您单击没有显式target属性的链接,浏览器只会在当前选项卡中打开新请求,即它只是对目标 URL 的另一个 GET 请求,但似乎情况并非如此

  • 在这种情况下,浏览器似乎正在对目标 URL 进行隐藏的后台获取(在 FF、Chrome 和 IE 中的行为相同),我什至在 F12 工具中都看不到。

  • F12 网络日志根本没有显示任何活动,除非在响应尚未设置为Content-Disposition: attachment错误的特定情况下 - 只有在这种情况下,我才能看到(失败的)HTTP GET 记录在网络请求列表中。

我想我可以在控制器中捕获任何异常并发送回一个名为“Error.csv”的虚拟文件,内容为“哈哈,不!” 或类似的东西,但那将是最后的手段......欢迎任何想法!

4

1 回答 1

4

如果用户单击链接,浏览器将跟随它-然后根据响应标头和浏览器配置,它将显示文件对话框或直接呈现-您无法真正更改该行为(除了使用 preventDefault when单击链接,这与目的不符)。

我建议仔细看看http://jqueryfiledownload.apphb.com/它可以让你做这样的事情:

$.fileDownload('some/file/url')
    .done(function () { alert('File download a success!'); })
    .fail(function () { alert('File download failed!'); });

然后您可以使用 jQuery 绑定下载操作。

于 2013-10-16T11:45:20.063 回答