jquery - 下载 <href ="blob:http://url/guid"download ="filename"/> 忽略下载属性

标签 jquery ajax asp.net-web-api download

根据一些在线教程和示例,我构建了一个文件下载系统,该系统在客户端上基于 jQuery,在服务器上基于 MS WebAPI。

无法提供文件的直接链接,因为 API 需要身份验证,因此文件 URL 是 API 端点,而不是文件位置。

在服务器上我有这个:

[HttpGet]
[Route("download/{filename}")]
public HttpResponseMessage DownloadFile(string filename)
{
    try
    {
        // https://gist.github.com/joeriks/3714093
        string path = string.Format("{0}/Exports/{1}", root, filename);

        HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
        var stream = new FileStream(path, FileMode.Open);
        result.Content = new StreamContent(stream);
        result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
        result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
        result.Content.Headers.ContentDisposition.FileName = "download.txt";
        return result;

    }
    catch (Exception ex)
    {
        throw new HttpResponseException(HttpStatusCode.InternalServerError);
    }
}

这将返回预期的响应:

HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Length: 4809
Content-Type: application/octet-stream
Expires: -1
Server: Microsoft-IIS/10.0
Content-Disposition: attachment; filename=download.txt
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, PUT, DELETE, GET, OPTIONS
Access-Control-Allow-Headers: content-Type, accept, origin, X-Requested-With, X-Authentication, X-Nonce, name
Date: Thu, 25 Oct 2018 13:07:25 GMT

响应中包含文本内容。 到目前为止,一切都如我所愿。

在客户端上,我使用以下方法来处理来自 API 的响应:

// https://stackoverflow.com/a/23797348
let disposition = jqXHR.getResponseHeader('Content-Disposition');

if (disposition && disposition.indexOf('attachment') !== -1) {
    let filename = "scada-download.txt";
    let matches = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/.exec(disposition);
    if (matches != null && matches[1]) filename = matches[1].replace(/['"]/g, '');

    let type = jqXHR.getResponseHeader('Content-Type');
    let blob = new Blob([data], { type: "text/csv" });

    var downloadUrl = URL.createObjectURL(blob);
    let $a = $("<a id='temp_download_link' style='display: none;' />").attr("href", downloadUrl).attr("download", filename);
    $("body").append($a);
    $a.trigger("click");
}

这正如宣传的那样,并向页面添加一个 anchor ,然后单击它触发下载。

下载成功,并保存具有正确内容的文件。

唯一不起作用的是,在我在(Chrome 69,FF:62)中测试过的两种浏览器中,提供的默认文件名只是一个 GUID。

API 和客户端代码目前都在我的本地开发机器上运行,http://127.0.0.1:9000/[client | api] 所以跨源不应该发挥任何作用。

对 api 的调用是通过 ajax 进行的。最终是 jQuery $.ajax() 方法

为了清楚起见,插入 DOM 的 anchor 是:

<a id="temp_download_link" style="display: none;" href="blob:http://127.0.0.1:9000/c2c5ffb5-3f22-4a57-8775-4e0bbfbfef9e" download="download.txt"></a>

Chrome提供的默认文件名是URL中的GUID,FF会生成一个看似互不相连的6个字符的随机字符串。

具体来说, 为什么浏览器会忽略 anchor 的 download="download.txt" 属性和 Content-Disposition: 附件;文件名=download.txt

更新:

我 fork 了这个 fiddle :

http://jsfiddle.net/Qjvb3/

并为 href 属性添加了一些其他值,似乎整个文件名设置充其量是片状的:

http://jsfiddle.net/yubjqwvs/

更新2

我已将工作示例中的链接复制到我的 fiddle 中,它可以在原始站点上使用,但不能从 fiddle 上使用。

http://jsfiddle.net/yubjqwvs/2/

我有一种感觉,答案将归结为“为什么它在 David Walsh 博客上有效,但在 fiddle 上不起作用?”

最佳答案

我个人用过downloadjs以避免在我的案例中出现类似问题:

  • 发出 AJAX 请求来下载文件;这只是一个带有适当 header 的 PHP 脚本 (Content-Disposition:attachment; filename="...")
  • 用户单击链接,该链接使用 hashchange 事件触发下载,我将 AJAX 响应传递给 downloadjs。我想使用 Blob URL 也可以完成同样的事情。

downloadjs的代码与jsfiddle非常相似松散地基于你的例子。它在 Firefox 63、Opera 56 上运行良好(我想它应该在 Chrome 上运行),但在 IE 11 上失败,但好吧,那就是 IE。

  • downloadjs 创建一个隐藏链接,超时设置为 66 毫秒(我想它是为了等待 DOM 准备好或类似的东西)。
  • 超时调用可能调用 native 处理程序的链接上的 click()

使用您的代码,并使用 click() 以及 document.getElementById() 而不是 jQuery,给我们这个 jsfiddle 。与 downloadjs 相反,我不使用 window.setTimeout 并且它工作得很好,至少在 Fx 63 中是这样。这可能只是绕过浏览器错误的一种方法。

就你的情况而言,我的猜测是,当你调用 trigger('click') 时,jQuery 不会触发默认处理程序,我无法理解,因为 trigger 文档似乎告诉我们确实如此:

As of jQuery 1.3, .trigger()ed events bubble up the DOM tree; an event handler can stop the bubbling by returning false from the handler or calling the .stopPropagation() method on the event object passed into the event. Although .trigger() simulates an event activation, complete with a synthesized event object, it does not perfectly replicate a naturally-occurring event.

To trigger handlers bound via jQuery without also triggering the native event, use .triggerHandler() instead. (quoted from jquery documentation)

也许默认的链接点击不被视为 jquery 的处理程序(?)并且不会被触发。

关于jquery - 下载 <href ="blob:http://url/guid"download ="filename"/> 忽略下载属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52990499/

相关文章:

javascript - JQuery 插件和原型(prototype),公开方法

c# - 带有 Unauthorize 状态代码和 Content//response 的 HttpResponseMessage 没有必需的 WWW-Authenticate header 字段

c# - 在 C# 中将 EF 对象作为普通数组返回

asp.net-mvc - MVC 流程的 OAuth 2.0

javascript - 传递一个 jquery 变量

javascript - 当包含 jQuery 脚本时,老式的 html onclick return false 在 IE 中不起作用

css - Jquery 事件绑定(bind)以选择焦点输入/输出

PHP 提交和处理表单的最佳且安全的方式

javascript - 如何使用 HTML、jQuery、数字 API

javascript - 在 Django View 中检索嵌套的 javascript 对象作为字典