Formdata image file isn't being caught by API call - javascript

I am using JavaScript to create an API call and send it to a corresponding Asp.Net Core function.
JavaScript:
function fileSubmit() {
var data = document.getElementById("myFile").files; //it should be noted that this successfully catches the file.
var formData = new FormData();
formData.append("files", data);
var url = "http://localhost/api/Surveys/123456/Units/987654/Images";
var xhr = new XMLHttpRequest();
xhr.open("POST", url, true);
xhr.setRequestHeader("Content-type", "image/jpeg");
xhr.send(formData);
}
.Net Core:
[HttpPost]
[Route("{Id:int:min(1)}/Units/{unitId:int:min(1)}/Images")]
[ProducesResponseType(typeof(IAPIResponse2<UploadImagesResponse>), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(IAPIResponse2<UploadImagesResponse>), StatusCodes.Status400BadRequest)]
public async Task<IActionResult> UploadImages([FromForm, Required] IList<IFormFile> files)
{
//do stuff
}
I am able to create and send the API call and it is caught by the Asp.Net function, but the files parameter is empty. The file list is successfully appended to the formData object in the JavaScript function, as far as I know.
What am I missing?

There are two problems with your JavaScript code above:
files is being sent incorrectly. If you look at the request, you'll see it's a bit confused and includes [object FileList] as part of the body.
To solve this issue, you'll want to iterate through the files and add them individually:
var files = document.getElementById("myFile").files;
var formData = new FormData();
for (var i = 0; i < files.length; i++) {
formData.append("files", files[i]);
}
If you are just sending the one file, you could simplify this:
var files = document.getElementById("myFile").files;
var formData = new FormData();
formData.append("files", files[0]);
You should not set the Content-Type header when making the request.
To solve this issue, simply remove your call to setRequestHeader. The Content-Type header will be set by the XHR process to be multipart/form-data with boundaries (see the RFC for the Multipart Content-Type).
Each part starts with an encapsulation boundary, and then contains a body part consisting of header area, a blank line, and a body area.
Due to the way this is structured, the Content-Type is specified on a per-file basis. If you are interested, have a look at the request in the developer tools once you've made the changes I have detailed.

Related

How to refactor a drag-and-drop file Chrome extension to resolve CORB errors

I have an old Chrome extension that added drag-and-drop functionality to a site with file uploads. The site has pages on one subdomain (ex: https://foo.site.com/page1.php, https://foo.site.com/page2.php..), and the upload endpoint is on another subdomain (ex: https://bar.site.com/upload.php). Starting in some previous Chrome version, the extension stopped working because of stricter CORS rules. The POST to upload the file seems to succeed, but the response is blocked with a CORB error, and I need the response to know where the file's new remote path is.
I've attempted to refactor by moving requests from the content script to the background script, per Google's guidelines. However, I can't figure out how to share a file drag-and-dropped onto the page with the background script. Here's some sample code:
content.js:
var setupDragAndDrop = function () {
(
document.getElementById("some_element")
).addEventListener("drop", function (e) {
for (var t = 0, s = e.dataTransfer.files.length; t < s; t++)
upload(e.dataTransfer.files[t], function (e) {
insertResponseOnPage(e); // Use the upload response to show the new remote path on the page
});
e.preventDefault();
});
},
var upload = function(file, callback) {
chrome.runtime.sendMessage(
{
need: "upload",
file: file,
callback: callback
}
);
}
background.js (there is some other logic that lets the message end up at this method, but it does end up here with the file and callback):
var upload = function(file, callback) {
var formData = new FormData();
formData.append('file', file);
const UPLOAD_URL = 'https://bar.site.com/upload.php';
var xhr = new XMLHttpRequest();
xhr.open('POST', UPLOAD_URL, true);
xhr.withCredentials = "true";
xhr.onload = callback;
xhr.send(formData);
};
This issue I'm seeing is that the file ending up on the background page is an empty object. I believe I read somewhere that whatever is sent with the message API needs to be JSON serializable, so I'm assuming File is not? I get the same behavior if I attempt to send a FormData object as well. I've also tried going down the route of somehow getting the file path instead and recreating the file in the background page, but apparently you can't get the path from a system file in JS for security reasons.
Is there any way to fix up this extension? I do not own the site this extension attempts to add functionality to, so I can't move the upload endpoint onto the same subdomain.

FormData Inserting Extra TExt

I'm using form data in Javascript to send my inputs to the server but I noticed something funky. In Firefox and Chrome it sends back extra text along with the data and adds it to the original value. Here is an example of what chrome outputs
------WebKitFormBoundaryq5GElQTvd3mbU5qE--
Here is my code. I am doing a PUT request.
var formData = new FormData();
formData.append('user','tester');
var req = new XMLHttpRequest();
req.onload=function(e){
console.log(this)
}
req.open('PUT','http://localhost/site_template/create_file.php',true);
req.send(formData);

Download file using Javascript from a bytearray

I have a button in my asp net app that when pressed I am calling a rest service that returns a bytearray.
This bytearray is actually a file that I need to start downloading in the browser when the button is pressed. How can I achieve this?
I am thinking along the lines of writing the bytearray to the response and setting the headers.
Is this thinking correct and does someone have some code samples?
---------Update on 3/25----------------
Thanks Justin but not yet what I need. Please look at this link it will return a file for download. What I need to do is have an event client side that will get this file for download without redirecting to this page. It has to be downloaded from my page and not this link.
http://ops.epo.org/3.0/rest-services/published-data/images/US/5000001/PA/firstpage.pdf?Range=1
If you check it out with Fiddler, you will see how the pdf is received as binary.
You can set the responseType as arraybuffer and access it that way. There is even a way to stream the data using onprogress events. JavaScript has come a long way.
var oReq = new XMLHttpRequest();
oReq.open("GET", "/myfile.png", true);
oReq.responseType = "arraybuffer";
oReq.onload = function (oEvent) {
var arrayBuffer = oReq.response; // Note: not oReq.responseText
if (arrayBuffer) {
var byteArray = new Uint8Array(arrayBuffer);
for (var i = 0; i < byteArray.byteLength; i++) {
// do something with each byte in the array
}
}
};
oReq.send(null);
https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest/Sending_and_Receiving_Binary_Data
If you mean that the webservice isn't returning binary data, and instead is JSON data like: [0,1,3,4] then that is a different issue.
As far as i know, the closest thing you can do with javascript is an ajax request that has the server parse the data as text

Use XPCOM to upload file/image on webpage

I am using an example found here. Mozilla developers
I am interested in this example.
function upload(postUrl, fieldName, filePath)
{
var formData = new FormData();
formData.append(fieldName, new File(filePath));
var req = new XMLHttpRequest();
req.open("POST", postUrl);
req.onload = function(event) { alert(event.target.responseText); };
req.send(formData);
}
But I can't understand what goes where on this example. filePath is understandable but postUrl , fieldName I can find. I am working on image uploading on the page that has Drag and Drop zone for image uploading. How can I use this function to upload the image on my website?
Check out the FormData documentation and XMLHttpRequest documentation.
fieldName The name of the (form) field whose data is contained in value.
postUrl The URL to which to send the request.
You should have a server-side endpoint that responds to the upload request.
For example:
upload('http://mysite.com/uploader.php', 'fileField', 'path/to/my/file.jpg');
Then if you are using PHP on the server-side; you can access that field value on the server-side like this:
$my_files = $_FILES['fileField'];

Is there any way to send binary data with XMLHttpRequest object?

I'am trying to send binary chunk with XMLHttpRequest
var xhr = new XMLHttpRequest();
var bindata = 0x0f0f;
xhr.open("POST", "binary_reader.php");
xhr.send(bindata);
But this approach not works. I've tried to provide Content-type: application/octet-stream, Content-encoding headers for xhr and they don't work either. I am suspect that there is no way to compose request of such kind.
I would appreciate any help.
XMLHttpRequest.sendAsBinary is obsolete. Link
As MDN mentioned, you can directly send binary typed array:
var myArray = new ArrayBuffer(512);
var longInt8View = new Uint8Array(myArray);
// generate some data
for (var i=0; i< longInt8View.length; i++) {
longInt8View[i] = i % 256;
}
var xhr = new XMLHttpRequest;
xhr.open("POST", url, false);
xhr.send(myArray);
Yes you can send binary data using XHR. All you need to do is set the appropriate headers and mime-type, and call the sendAsBinary method instead of the simple send method. For example:
var req = new XMLHttpRequest();
req.open("POST", url, true);
// set headers and mime-type appropriately
req.setRequestHeader("Content-Length", 741);
req.sendAsBinary(aBody);
W3C has introduced Blob type to XMLHttpRequest in the latest specification. Currently I haven't seen any implementation so far but in near future this is definitely the way to download and upload binary data with XMLHttpRequest.
The section "Handling binary data" here describes how to send and receive binary data via XMLHttpRequest.

Categories

Resources