如何为 HTTP GET 请求设置标头,并触发文件下载?

IT技术 javascript ajax http-headers download
2021-02-03 17:13:22

更新20140702:

(但我将其他答案之一标记为已接受而不是我自己的,因为它使我成功了一半,并奖励了我的努力)


似乎无法通过与 的链接设置 HTTP 请求标头<a href="...">,只能使用XMLHttpRequest.

但是,链接到的 URL 是一个应该下载的文件(浏览器不应导航到其 URL),我不确定这是否可以使用 AJAX 完成。

此外,返回的文件是一个二进制文件,AJAX 并不适用于此。

如何使用添加了自定义标头的 HTTP 请求触发文件下载?

编辑:修复断开的链接

5个回答

两种方法可以下载HTTP 请求需要设置标头的文件

第一个归功于@guest271314,第二个归功于@dandavis。

第一种方法是使用 HTML5 File API 创建临时本地文件,第二种方法是使用 base64 编码结合数据 URI。

我在我的项目中使用的解决方案对小文件使用base64编码方式,或者当File API不可用时,否则使用File API方式。

解决方案:

        var id = 123;

        var req = ic.ajax.raw({
            type: 'GET',
            url: '/api/dowloads/'+id,
            beforeSend: function (request) {
                request.setRequestHeader('token', 'token for '+id);
            },
            processData: false
        });

        var maxSizeForBase64 = 1048576; //1024 * 1024

        req.then(
            function resolve(result) {
                var str = result.response;

                var anchor = $('.vcard-hyperlink');
                var windowUrl = window.URL || window.webkitURL;
                if (str.length > maxSizeForBase64 && typeof windowUrl.createObjectURL === 'function') {
                    var blob = new Blob([result.response], { type: 'text/bin' });
                    var url = windowUrl.createObjectURL(blob);
                    anchor.prop('href', url);
                    anchor.prop('download', id+'.bin');
                    anchor.get(0).click();
                    windowUrl.revokeObjectURL(url);
                }
                else {
                    //use base64 encoding when less than set limit or file API is not available
                    anchor.attr({
                        href: 'data:text/plain;base64,'+FormatUtils.utf8toBase64(result.response),
                        download: id+'.bin',
                    });
                    anchor.get(0).click();
                }

            }.bind(this),
            function reject(err) {
                console.log(err);
            }
        );

请注意,我没有使用 raw XMLHttpRequest,而是使用ic-ajax,并且应该与jQuery.ajax解决方案非常相似

另请注意,您应该使用与正在下载的文件类型相对应的任何内容替换text/bin.bin

的实现FormatUtils.utf8toBase64 可以在这里找到

现在看起来像那个 404,我最近在发布时一定打破了一些别名。这是更新的链接:blog.bguiz.com/2014/07/02/...
2021-03-15 17:13:22
它有效,仍然不是很高兴,因为该文件首先被静默下载,并且在下载时不会出现在下载中。
2021-03-24 17:13:22
另外值得一提的是您在优秀的博客文章中提出的观点,即在服务器收到包含正确标头的常规请求,通过创建不需要标头的临时下载路径来实现此服务器端。
2021-03-29 17:13:22
你能看到这个链接吗?stackoverflow.com/questions/48189365/...
2021-04-10 17:13:22
看起来你再次移动它,这里的链接:blog.bguiz.com/2014/07/03/...谢谢详细解答!
2021-04-12 17:13:22

尝试

html

<!-- placeholder , 
    `click` download , `.remove()` options ,
     at js callback , following js 
-->
<a>download</a>

js

        $(document).ready(function () {
            $.ajax({
                // `url` 
                url: '/echo/json/',
                type: "POST",
                dataType: 'json',
                // `file`, data-uri, base64
                data: {
                    json: JSON.stringify({
                        "file": "data:text/plain;base64,YWJj"
                    })
                },
                // `custom header`
                headers: {
                    "x-custom-header": 123
                },
                beforeSend: function (jqxhr) {
                    console.log(this.headers);
                    alert("custom headers" + JSON.stringify(this.headers));
                },
                success: function (data) {
                    // `file download`
                    $("a")
                        .attr({
                        "href": data.file,
                            "download": "file.txt"
                    })
                        .html($("a").attr("download"))
                        .get(0).click();
                    console.log(JSON.parse(JSON.stringify(data)));
                },
                error: function (jqxhr, textStatus, errorThrown) {
                  console.log(textStatus, errorThrown)
                }
            });
        });

jsfiddle http://jsfiddle.net/guest271314/SJYy3/

@ guest271314 感谢您的回答,这适用于较小的文件,但不适用于较大的文件(> 1mb)。我将您的解决方案标记为已接受,因为它有很大帮助。我的实际解决方案可以在这里找到
2021-03-30 17:13:22

我正在添加另一个选项。上面的答案对我来说非常有用,但我想使用 jQuery 而不是 ic-ajax(当我尝试通过 bower 安装时,它似乎与 Ember 有依赖关系)。请记住,此解决方案仅适用于现代浏览器。

为了在 jQuery 上实现这一点,我使用了jQuery BinaryTransport这是一个很好的插件,可以读取二进制格式的 AJAX 响应。

然后你可以这样做来下载文件并发送标题:

$.ajax({
    url: url,
    type: 'GET',
    dataType: 'binary',
    headers: headers,
    processData: false,
    success: function(blob) {
        var windowUrl = window.URL || window.webkitURL;
        var url = windowUrl.createObjectURL(blob);
        anchor.prop('href', url);
        anchor.prop('download', fileName);
        anchor.get(0).click();
        windowUrl.revokeObjectURL(url);
    }
});

上面脚本中的变量意味着:

  • url: 文件的 URL
  • headers:带有要发送的标头的 Javascript 对象
  • fileName:用户下载文件时将看到的文件名
  • 锚点:它是模拟下载所需的 DOM 元素,在这种情况下必须用 jQuery 包装。例如$('a.download-link')
简单明了。这可能会有所帮助 var anchor = $("<a></a>"); anchor.css("显示", "无"); $("body").append(anchor); anchor.prop('href', url); anchor.prop('下载', 文件名); 锚点.get(0).click(); windowUrl.revokeObjectURL(url); 锚点。删除();
2021-04-11 17:13:22
非常干净和简单的解决方案!+1
2021-04-12 17:13:22

我想在这里发布我的解决方案,它是通过 AngularJS、ASP.NET MVC 完成的。该代码说明了如何通过身份验证下载文件。

WebApi 方法和辅助类:

[RoutePrefix("filess")]
class FileController: ApiController
{
    [HttpGet]
    [Route("download-file")]
    [Authorize(Roles = "admin")]
    public HttpResponseMessage DownloadDocument([FromUri] int fileId)
    {
        var file = "someFile.docx"// asking storage service to get file path with id
        return Request.ReturnFile(file);
    }
}

static class DownloadFIleFromServerHelper
{
    public static HttpResponseMessage ReturnFile(this HttpRequestMessage request, string file)
    {
        var result = request.CreateResponse(HttpStatusCode.OK);

        result.Content = new StreamContent(new FileStream(file, FileMode.Open, FileAccess.Read));
        result.Content.Headers.Add("x-filename", Path.GetFileName(file)); // letters of header names will be lowercased anyway in JS.
        result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
        result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
        {
            FileName = Path.GetFileName(file)
        };

        return result;
    }
}

Web.config 文件更改为允许在自定义标头中发送文件名。

<configuration>
    <system.webServer>
        <httpProtocol>
            <customHeaders>
                <add name="Access-Control-Allow-Methods" value="POST,GET,PUT,PATCH,DELETE,OPTIONS" />
                <add name="Access-Control-Allow-Headers" value="Authorization,Content-Type,x-filename" />
                <add name="Access-Control-Expose-Headers" value="Authorization,Content-Type,x-filename" />
                <add name="Access-Control-Allow-Origin" value="*" />

Angular JS 服务部分:

function proposalService($http, $cookies, config, FileSaver) {
        return {
                downloadDocument: downloadDocument
        };

    function downloadFile(documentId, errorCallback) {
    $http({
        url: config.apiUrl + "files/download-file?documentId=" + documentId,
        method: "GET",
        headers: {
            "Content-type": "application/json; charset=utf-8",
            "Authorization": "Bearer " + $cookies.get("api_key")
        },
        responseType: "arraybuffer"  
        })
    .success( function(data, status, headers) {
        var filename = headers()['x-filename'];

        var blob = new Blob([data], { type: "application/octet-binary" });
        FileSaver.saveAs(blob, filename);
    })
    .error(function(data, status) {
        console.log("Request failed with status: " + status);
        errorCallback(data, status);
    });
};
};

FileUpload 的module依赖项:angular-file-download(gulp install angular-file-download --save)。注册如下所示。

var app = angular.module('cool',
[
    ...
    require('angular-file-saver'),
])
. // other staff.

纯jQuery。

$.ajax({
  type: "GET",
  url: "https://example.com/file",
  headers: {
    'Authorization': 'Bearer eyJraWQiFUDA.......TZxX1MGDGyg'
  },
  xhrFields: {
    responseType: 'blob'
  },
  success: function (blob) {
    var windowUrl = window.URL || window.webkitURL;
    var url = windowUrl.createObjectURL(blob);
    var anchor = document.createElement('a');
    anchor.href = url;
    anchor.download = 'filename.zip';
    anchor.click();
    anchor.parentNode.removeChild(anchor);
    windowUrl.revokeObjectURL(url);
  },
  error: function (error) {
    console.log(error);
  }
});