On Firefox 3.6 and Chrome, using xhr.send(file) just puts the raw contents into the body of the request and it is not a true multipart/form-data upload.
Tried doing this: http://kaply.com/weblog/2010/05/20/post-multipart-form-xhr/
But, can't really mix string with File contents during send().
Any workarounds?
xhr.sendAsBinary() is non-standard. Instead, use xhr.send(FormData), which does create a multipart/form-data request, allows appending files, and arbitrary form data.
var formData = new FormData();
formData.append(file.name, file);
var xhr = new XMLHttpRequest();
xhr.open('POST', '/upload', true);
xhr.onload = function(e) { ... };
xhr.send(formData); // multipart/form-data
See http://www.html5rocks.com/en/tutorials/file/xhr2/#toc-send-formdata
The key thing is using sendAsBinary(body) istead of send(body). See the last comment on the page you linked!
Related
For learning purposes, I'd like to know how to create a FormData object.
Using the FormData api, I can send a file like this :
let data = new FormData();
data.append('avatar', avatar);
var xhr = new XMLHttpRequest();
xhr.open('POST', '/api_enpoint', true);
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.setRequestHeader('X-CSRF-TOKEN', document.head.querySelector('meta[name="csrf-token"]').content);
xhr.send(data);
"avatar", appended to the FormObject, is a "File" object.
How can I perform the "FormData" work manually ?
That is, creating the full object, and send it with xhr.send(data)
Is there an example somewhere ? I can't find code that works.
I've read the RFC, but it does not help me that much.
Edit:
My question is different than How to manually create multipart/form-data
My case is specifically for sending a file. And the other question does not handle that. There's no working solution at all for both questions.
I am trying to send pdf file from my express server using the client when requested like this:
res.setHeader('Content-Type', 'application/pdf');
res.setHeader('Content-Disposition', 'attachment; filename=test.pdf');
fs.createReadStream('test.pdf').pipe(res);
And then on the client side I am trying to download it by taking the resulting string converting it to a url and downloading from there.
var blob = new Blob[pdfString], { type: 'application/pdf' });
var url = window.URL;
var downloadUrl = url.createObjectURL(blob);
However the resulting file is two empty pages and I beleive think it might be because the resulting file is url is to large? If anyone could figure out whats wrong here or tell me of a better way to do it that would be awesome.
I was able to figure it out using XMlHttpRequest:
var req = new XMLHttpRequest();
req.open('GET', path , true);
req.responseType = "arraybuffer";
req.onload = (event) => {
downloadPdf(req.response); //This is where I convert to blob
}
req.send();
I am using an external payment site to redirect to my own website. I need some of the form data in the headers and I cannot figure out how to grab the data. Here is a screenshot:
Inside the headers tab, I want to get the information from the Form Data tab.
The code below is what I was able to find regarding getting headers, but the problem is it only grabs the code from the ResponseHeaders tab. And req does not have any function to get the form data.
var req = new XMLHttpRequest();
req.open('GET', document.location, false);
req.send(null);
var headers = req.getAllResponseHeaders().toLowerCase();
I want to see if there is a function where I can do something like
var formData = req.getFormData().toLowerCase();
There is no way, in browser-side JavaScript, to get information about the request that was used to get the current page from the server.
If you want access to it, you'll need to use server side code to dynamically generate the page and include it in the DOM (perhaps as a JavaScript object in a <script> element, or as a data-* attribute, or in <meta> elements) and then use JS to extract it from the DOM.
The mozilla site provides an example (https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/getResponseHeader)
var client = new XMLHttpRequest();
client.open("GET", "unicorns-are-teh-awesome.txt", true);
client.send();
client.onreadystatechange = function() {
if(this.readyState == this.HEADERS_RECEIVED) {
console.log(client.getResponseHeader("Content-Type"));
}
}
But fetch is nicer (see https://developer.mozilla.org/en-US/docs/Web/API/Response/headers):
fetch(myRequest).then(function(response) {
console.log(response.headers); // returns a Headers{} object
response.blob().then(function(myBlob) {
var objectURL = URL.createObjectURL(myBlob);
myImage.src = objectURL;
});
});
I need to use JQuery ajax to post a complex and sensitive data object (nested objects, arrays, and Personally Identifiable Information) to my server, where a PDF is generated and returned to the client. The client browser then should open the PDF in a new window.
Because of the nature of the data the request neither can nor should be an encoded URL - it must include the data as a JSON body.
The other questions/answers on this subject did not solve the problem in my case or do not do so completely.
Solution
POST with the data in the body as JSON.
Set the expected Content-Type of the response to arraybuffer (on the client and server).
When the request has complete successfully, convert the response to a Blob.
Create an object url to the Blob and open it in a new window.
Notes
JQuery ajax does not support the arraybuffer Content-Type so the base JavaScript xhr must be used (if you don't have any other options).
Internet Explorer has its own functionality for handling and displaying Blob's, so a special case is needed.
Supported browsers does not include IE9
Code
RequestPdf = function (url, data) {
var request = new XMLHttpRequest(), file, fileURL;
request.open("POST", url);
request.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
request.responseType = "arraybuffer";
request.send(data);
request.onreadystatechange = function () {
if (request.readyState === 4 && request.status === 200) {
file = new Blob([request.response], { type: 'application/pdf' });
if (window.navigator && window.navigator.msSaveOrOpenBlob) { // IE
window.navigator.msSaveOrOpenBlob(file);
} else {
fileURL = URL.createObjectURL(file);
window.open(fileURL);
}
}
};
};
I'm writing a chrome extension content script which will embed itself on some pages, and when there are certain file type links (.doc, .torrent, etc) it will download that file, and then do a file POST to a python web server which will save that file. The python server is working, and handles a normal multipart/form-data POST request, and successfully saves the file when I use the html interface I wrote for it.
I have javascript downloading the file properly:
var req = new XMLHttpRequest();
req.open('GET', 'http://foo.com/bar.torrent', false);
req.overrideMimeType('text/plain; charset=x-user-defined');
req.send(null);
if (req.status != 200) return '';
var response = req.responseText;
And then when I try to create a POST request and upload it
// Define a boundary, I stole this from IE but you can use any string AFAIK
var boundary = "---------------------------7da24f2e50046";
var xhr = new XMLHttpRequest();
var body = '--' + boundary + '\r\n'
// Parameter name is "file" and local filename is "temp.txt"
+ 'Content-Disposition: form-data; name="upfile";'
+ 'filename="temp.torrent"\r\n'
// Add the file's mime-type
+ 'Content-type: application/bittorrent\r\n\r\n'
+ response + '\r\n';
//+ boundary + '--';
xhr.open("POST", "http://python.server/", true);
xhr.setRequestHeader(
"Content-type", "multipart/form-data; boundary="+boundary
);
xhr.onreadystatechange = function ()
{
if (xhr.readyState == 4 && xhr.status == 200)
alert("File uploaded!");
}
xhr.send(body);
It thinks that it uploaded successfully, but when I try to open the file it says the data is corrupted. I think this is some kind of encoding issue, but I'm not 100% sure.
Any thoughts would be very helpful.
Your upload method does not work, because all binary characters are encoded as UTF-8. I posted the explanation and solution in an answer at this question.
In your case, you don't need to manually create the post data. Request the initial data in a smart way, and use the FormData object to post the binary data. For instance:
var x = new XMLHttpRequest();
x.onload = function() {
// Create a form
var fd = new FormData();
fd.append("upfile", x.response); // x.response is a Blob object
// Upload to your server
var y = new XMLHttpRequest();
y.onload = function() {
alert('File uploaded!');
};
y.open('POST', 'http://python/server/');
y.send(fd);
};
x.responseType = 'blob'; // <-- This is necessary!
x.open('GET', 'http://foo.com/bar.torrent', true);
x.send();
Note: I replaced false with true at the initial request. Avoid using synchronous XMLHttpRequest when it's also possible to asynchronously create the request.
If you don't understand the answer, here are more examples with thorough explanations:
XMLHttpRequest: Multipart/Related POST with XML and image as payload - FormData is not used, but the post data is manually created instead.
Upload a File in a Google Chrome Extension - A sample Chrome extension which uses Web Workers (with a FormData polyfill) to upload files
Google chrome rehost image extension - Scrapes an image from the page, and upload the image to imgur using a Chrome extension.