最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - AJAX File Download with custom header - Stack Overflow

programmeradmin0浏览0评论

I want to send a request to a URL which provides me a file download dialog box. At the same time the server needs certain parameters in the request header. I want to insert a custom header in the request and get a file in response. Is there any way we can achieve this?

I want to send a request to a URL which provides me a file download dialog box. At the same time the server needs certain parameters in the request header. I want to insert a custom header in the request and get a file in response. Is there any way we can achieve this?

Share Improve this question edited Jan 8, 2019 at 23:35 Manglu 11.3k12 gold badges47 silver badges62 bronze badges asked Nov 27, 2012 at 9:33 amitamit 2515 silver badges8 bronze badges 2
  • 1 What type of info are you adding to the request header? Concerning the response, you just send back what you want with something like this Response.Clear(); Response.ContentType = "application/text"; Response.ContentEncoding = _ex.Encoding; Response.AddHeader("content-disposition", String.Format("attachment; filename={0}", _ex.FileName)); Response.BinaryWrite(_ex.Output); Response.End(); – Nick.T Commented Nov 27, 2012 at 9:38
  • This is not an exact duplicate question, but is specifically for GET requests, but the answers there may be useful. – Robin Green Commented Nov 11, 2015 at 8:47
Add a comment  | 

4 Answers 4

Reset to default 8 +50

Try using a element with data-* set to headers for request , $.ajax() with headers option set to a element data-headers object .

At $.ajax() success set a element href to response as Blob within objectURL, download attribute to file.name or temporary file name , call .click() on a element to activate "Save File" dialog .

$(document).ready(function() {
  $("input[type=button]").click(function() {
    // set `data-headers` object
    var el = $("[data-headers]");
    el.data("headers")["x-custom-headers"] = $("input[type=text]")[0].value 
      || el.data("headers")["x-custom-headers"];
    $.ajax({
      url: URL.createObjectURL(new Blob([$("textarea").val()], {
        type: "text/plain"
      })),
      type: "GET",
      // set `headers` to `a` element `data-headers` object
      headers: $("[data-headers]").data("headers"),
      beforeSend: function(jqxhr) {
        console.log(this.headers);
        alert("custom headers" + JSON.stringify(this.headers));
      },
      success: function(data, textStatus, jqxhr) {
        var file = new Blob([data], {
          "type": jqxhr.getResponseHeader("Content-Type")
        });
        console.log(data, file);
        $("textarea, input[type=text]").val("");
        $("a")
          .attr({
            "href": URL.createObjectURL(file),
            "download": file.name || "file-" + $.now()
          }).on("click", function() {
            $(this).remove()
          })
          .get(0).click();
      },
      error: function(jqxhr, textStatus, errorThrown) {
        console.log(textStatus, errorThrown)
      }
    });
  })
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">
</script>
<textarea maxlength="5" placeholder="echo"></textarea>
<br>
<!-- set `x-custom-header` to `input type="text"` value -->
<input type="text" maxlength="5" placeholder="set request header" />
<br />
<input type="button" value="download" />
<!-- set default `x-custom-header` to "123" -->
<a data-headers='{"x-custom-headers":"123"}'></a>

From what I understand is that you want to request a file from the web that requires a authentication header but can't be downloaded with a simple link.

What you need to do then is to make a ajax call with the authentication header to download the data as a blob. Then save the data from the client side


jQuery's ajax/get methods dosen't support the responseType = blob

So this example is using the latest Fetch API in Blink and Firefox. It also uses the FileSaver.js to save a client-side generated blob in versus ways to handle cross browser issues.

fetch("/", {headers: {"X-mashape-key": "XXXXXX-4-YYYYYY"}})
    .then( response => {
        // we can get the filename if the
        // response headers contains Content-Disposition
        var cd = response.headers.get("Content-Disposition");
        var name = cd && cd.match(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/)[1];

        response.blob().then( 
            blob => window.saveAs(blob, name || "index.html")
        )
    })

It also use some new suger syntax that is available in es6 that can be transpiled to es5 with babel or traceur

If you don't include a fetch polyfill and need to support older browsers - Then you need to do it the old fashion way with XHR

var xhr = new XMLHttpRequest();
xhr.responseType = 'blob';
xhr.open("get", "/");
xhr.setRequestHeader("X-mashape-key", "XXXXXX-4-YYYYYY");
xhr.send();
xhr.onload = function(){
    var cd = xhr.getResponseHeader("Content-Disposition")
    var name = cd && cd.match(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/)[1];

    window.saveAs(xhr.response, name || "index.html")
}

Maybe I don't get your point.

What I think is like this:

//server xxx.php
//omit some code
echo '<a href="file_path" id="download">file_name</a>';

//browser
ajax({
    url: 'http://xxxx/xxx.php',
    success: function(html){
        //append to dom and TODO other manipulations
        $(dom).append(html);
        $('#download').trigger('click');
        $(dom).remove(html);
    }
})

Ok, I checked in an old application I had and here is a sample. You'll need to adapt but the idea is here. This first part is part of an Request interceptor attribute that is placed on the WebMethod. The whole interceptor is quite complex because it manages several cases.

int byteSize = 262144;
byte[] data = new byte[byteSize];

if (!String.IsNullOrEmpty(myfileName))
{
    _context.Response.AddHeader("Content-disposition", "attachment; filename=\"" + myfileName+ "\"");
}

_context.Response.ContentType = DefaultContentType;
_context.Response.Cache.SetCacheability(HttpCacheability.Private);
_context.Response.Cache.SetExpires(DateTime.UtcNow.AddHours(1));
_context.Response.Buffer = false;
_context.Response.BufferOutput = false;
_context.Response.AddHeader("Content-length", myStreamSize.ToString());

try
{
    int counter = 0;
    int bytesRead = mystream.Read(data, 0, byteSize);
    while ((long)counter < myStreamSize|| bytesRead > 0)
    {
        counter += bytesRead;
        if (bytesRead < byteSize)
        {
            byte[] outBuf = new byte[bytesRead];
            Array.Copy(data, outBuf, bytesRead);
            _context.Response.BinaryWrite(outBuf);
        }
        else
        {
            _context.Response.BinaryWrite(data);
        }
        bytesRead = mystream.Read(data, 0, byteSize);
    }
}
finally
{
    mystream.Close();
    mystream.Dispose();
}
_context.Response.End();

This is the second part in the Javascript on the client side. We used ExtJS instead of jQuery.

downloadFile: function(url, getArgs) {
    if( !this.iframe )
    {
        this.iframe = document.createElement("iframe");
        this.iframe.className = "x-hidden";
        document.body.appendChild(this.iframe);
    }

    var args = Ext.urlEncode(getArgs);
    url = url + (args ? ("?" + args) : "");
    this.iframe.src = url;
}

The click of a button would call this function and give it the URL to the WebMethod and eventually extra args to pass. The idea on the JS side is to create a hidden iFrame that would take the URL and would then prompt the user to download.

I hope it helps out

发布评论

评论列表(0)

  1. 暂无评论