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 |4 Answers
Reset to default 8 +50Try 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
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