Upload a file with PUT/POST method on POSTMAN - javascript

I am trying to upload a file with POSTMAN to this URL
http://localhost:3000/bucket/test/files/
And should got result in my controller there :
put(request, response, args) {
//HERE IN THE REQUEST.BODY
console.log(request.body)
let fileManager = request.modules.VMFile;
let mimeTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/x-icon', ' video/mpeg', 'text/html', 'video/x-msvideo', 'application/msword', 'application/pdf', 'application/vnd.ms-powerpoint', 'application/x-rar-compressed'];
let maxFileSize = 4 * 1024 * 1024;
fileManager.initUpload(mimeTypes, maxFileSize);
fileManager.receive((files) => {
fileManager.forEachFileContent(files, (file, content) => {
minioClient.putObject(request.body.bucket, request.body.name, content, file.size, file.mimetype, function (err, etag) {
response.setData("File uploaded").apply();
return console.log(err, etag)
})
});
fileManager.clearFilesFromTmp(files);
});
}
In POSTMAN I got this :
With nothing on headers but I could only PUT (or POST, I tried to change my route with POST but same issue) the name and bucket field... I got nothing on my files field...

While using Postman especially when you test file upload ensure that,
in Headers:
The Content-type field has been set as multipart/form-data in Headers.
in Body:
form-data option should remain as default.
Choose File option instead of text from the dropdown on the right side.
Type File in the text box where the placeholder is key.

You might be doing it right but sometimes POSTMAN does not work well. I wrote an API to accept both text and file.
While invoking service from Postman.
I set Content-Type as "application/json" and Accept as "application/json".
In body I pass the text and file
It was not working, I tried multiple times. I shut down postman and my laptop.
Woke up the next morning hit again and it worked. Below is the image of the working request.

Not all of David's answer worked for me when using express-fileupload. In short, I don't require the Content-Type header when using express-fileupload.
Note, these steps are for npm / express-fileupload / Postman
Ensure the header Content-Type is disabled. Setting this forces req.files to be undefined.
As per Davids answer, use form-data and set the key to whatever you require, and upload the file.
If you console.log(req.files.YOUR_KEY) in your express app, you should have an object with the uploaded file, in my case req.files.file.
Here's what postman should look like (once again, disable the Content-Type header):
Here's the output within the console when using console.log(req.files):

Related

Javascript object coming through empty on server side

I have a client-side script running to send the string "Y" to the server. I set up a console.log on the client-side (which you can see below) and another on the server-side. The one on the client-side works, but the one logs an "empty" object.. it just shows "{}".
How do I get my data to stay in the object?
const status = "Y";
const options = {
method: 'POST',
headers: {
'Content-type': 'application/json'
},
body: status
fetch('/events/<%- event.id %>/prompt', options)
console.log(options.body)
Here's my route for context:
router.route('events/:id/prompt')
.get(catchAsync(events.showPrompt))
.post(catchAsync(events.checkIn))
And my controller:
module.exports.checkIn = async(req, res) => {
console.log(req.body);
}
How do I get the object to come through to the server?
For sending "y" as the content and receiving that in Express, you need two things:
You need to make sure the content-type is set to text/plain on the request.
You need the appropriate middleware that will read that text/plain body.
app.use(express.text())
Then, you will find the body in req.body within any express request handler registered after the above middleware.
You could pick different content-types also such as application/json, the corresponding middleware for that content-type app.use(express.json())` and then format the body data in that format.
It's important to realize that Express does not by itself read the body of an incoming request. It reads the headers, but not the body by default. If you want the body to be read, then you need middleware that is looking for whatever content-type the incoming request has, reads the body, parses it from whatever it's format is and puts the resulting parsed data into req.body. Express comes with a number of built-in middleware for popular content-types.
Status is a string. However body have to take a object with key-value pair. If send like with like below, then you get object which contains status on the backend side.
body: {status: status}
Problem from :
Client : you choose Content-type': 'application/json' , so your body must be json format , something like body : { status } . Make sure you sent exact object with browser debug , because some call api package can change value of request.
Server : Some nodejs framework need parse the value is sent from client before read it (Exp : app.use(express.json()) with Express)

Can not PUT file to google cloud storage bucket from JS in browser

I am using google-cloud-storage to generate a presigned URL to upload a file from the browser.
BUCKET.cors = [
{
"origin": ["*"],
"responseHeader": [
"Content-Type",
"x-goog-resumable"],
"method": ['PUT', 'POST'],
"maxAgeSeconds": 3600
}
]
BUCKET.patch()
blob = BUCKET.blob(blob_name)
url = blob.generate_signed_url(
version="v4",
# This URL is valid for 15 minutes
expiration=datetime.timedelta(minutes=15),
# Allow PUT requests using this URL.
method="PUT",
content_type="application/octet-stream",
)
The URL I get back looks like this. The blob_name I use is "<UUID>/<UUID>/test.png".
I then PUT with fetch to the returned URL.
const {signed_url} = await(await fetch(baseUrl + "/upload/signed?blob_name=" + path, {
credentials: "include",
})).json();
console.log('url', signed_url);
// upload to google
const url = await (await fetch(signed_url, {method: "PUT", body: file}) ).json()
Two problems occur
I get a CORS error - the PUT response does not include the CORS-Allow-Origin: "*" header.
When I bypass the first problem by using a CORS plugin I get the following response:
<?xml version='1.0' encoding='UTF-8'?><Error><Code>SignatureDoesNotMatch</Code><Message>The request signature we calculated does not match the signature you provided. Check your Google secret key and signing method.</Message><StringToSign>GOOG4-RSA-SHA256
20210910T200720Z
20210910/auto/storage/goog4_request
3df68a505fbb635cc4092462461b715ad31b4e83db668726ca5d87ebe1d64d9a</StringToSign><CanonicalRequest>PUT
/my-project-dev/edb5b48fcd724ab4a46afff3da5efa20/5b76eed38ed2473ea7c0b83e0e1d081c/52b675f15e2147849c911fe4f35951e9/test.png
X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=dev-laptop%40my-project.iam.gserviceaccount.com%2F20210910%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20210910T200720Z&X-Goog-Expires=900&X-Goog-SignedHeaders=content-type%3Bhost
content-type:image/png
host:storage.googleapis.com
content-type;host
UNSIGNED-PAYLOAD</CanonicalRequest></Error>
I tried finding JS fetch examples on stackoverflow and the gcloud documentation site. I also checked if there is an option for the python library that I am missing. Now I am out of options. It seems that the storage buckets were not designed for this use case. Help would be greatly appreciated.
As mentioned by Mabel A. in the comments:
The problem was a mismatch of the content type in the creation of the PSL.
I needed to have content-type: application/octet-stream when uploading the file.

HTTP Content-Length header calculation in javascript

I am new in javascript and node-js. I have an issue in calling a rest endpoint. My problem is when I try to call the endpoint using Postman everything is ok. I can see the calculated Content-Length header in Postman console. But when I try to call the same endpoint in javascript something is wrong because the calculated Content-Length is a bit lower than the calculated one by Postman. Here is my node.js code that I am using to call the endpoint. Note that the API is multipart API that is used for uploading the files.
file = fs.readFileSync('/Users/.../Documents/doc.pdf')
form = new FormData()
form.append('file', file)
headers = Object.assign({'Content-Length': form.getLengthSync() }, form.getHeaders())
config = {
method: 'post',
url: 'https://staging:...',
headers: headers,
data : form
};
axios(config).then((res) ->
console.log("The file is posted successfully. status is : " + res.status)
).catch((err) ->
console.log("The error occurred in posting file : " + err)
)
Can you please tell me what is missing here? for example for a specific file that I am testing the postman calculated value is 388 but the code calculated it as 379 for the same file.
Note: when I hardcode the value with the value from Postman everything is ok.
Issue #426 in the form-data repository seems to describe a solution for your problem.
I gave it a try locally and managed to get the desired results by applying what described in the issue:
const filePath = '/Users/.../Documents/doc.pdf';
const form = new FormData();
let options = {
knownLength: fs.statSync(filePath).size
}
form.append(
'file',
fs.createReadStream(filePath),
options,
);
I gather the issue is related to the acclaration made in the getLengthSync specification, which states that stream lengths' aren't calculated, hence the extra step that must be taken in order to provide the correct file length to the FormData instance.

Save File through JQuery AJAX Call

I am using JQuery to send an AJAX request to a Node server (using Hapi). The server responds with a PDF file correctly, but I am trying to save the file locally. The catch is that the PDF should only return if the POST sent the right data. It's "protected" in other words and I don't want to just expose it publicly.
Frontend code:
$.get('http://localhost:3000').done(function (data) {
console.log(data);
});
Backend code:
server.route({
method: 'GET',
path: '/',
handler: async (request, h) => {
return h.file('./static/sample.pdf', {
mode: 'attachment',
filename: 'sample.pdf'
})
}
});
I receive the data but nothing happens in the front-end UI. How can I download the PDF that is sent automatically?
You can achieve that with html5 using
Download it!
Notice that this works only for same-origin URLs, or the blob: and data: schemes. And this gets overridden by the Content-Disposition header from the server.
If you want to do this programatically you could do this
const element = document.createElement("a")
element.setAttribute(
"href",
// you could also use base64 encoding here like data:application/pdf;base64,
"data:text/plain;charset=utf-8," + encodeURIComponent('pdf binary content here')
)
element.setAttribute("download", "file.pdf")
element.style.display = "none"
document.body.appendChild(element)
element.click()
document.body.removeChild(element)
Anyway this is only a useful method if u want to create/modify the downloaded data from the client side, but if u are getting it as it is from the server side then its better just to open a new url, letting the browser handle it.

IE tries to download JSON in ASP. NET MVC 3

I was trying to return Json from my action and after that IE tried to download it and showed me save dialog.
I tested it in Firefox, and there it works fine.
return Json(new { success = false, message = ex.Message }, "application/json");
What is the reason of that behavior and how can I solve that issue?
After that in Javascript part I try this
if (responseJSON.success == false) {
alert(responseJSON.message);
cancel();
}
But IE doesn't show alert anyway. It brings me save dialog.
I tried to change "application/json" with "text/plain" and save dialog disappeared, but I am not able to see alert yet. What am I missing?
EDIT:
Here is my complect Javascript, I am using Valums qquploader(ex-Ajaxupload) for uploading images
var uploader = new qq.FileUploader({
element: document.getElementById("image-upload"),
action: '/Home/ImageUpload',
allowedExtensions: ['jpg', 'png', 'gif'],
sizeLimlit: 2048,onComplete: function (id, fileName, responseJSON) {
if (responseJSON.success == false) {
alert(responseJSON.message);
cancel();
}
else {
alert("success");
//some code here
}
}
});
I had tested with alert("success"); in my else part and forwarded json as "text/plain" and after that I saw the alert. But in that time responseJSON.success != false for me. Have you any suggestions about that?
I've solved that with this trick
return Json(new { success = false, message = ex.Message }, "text/html");
And now it works. But can me anyone explain why it works with text/html, and didn't work with application/json and text/plain. First is trying to download JSON and second is returning undefined properties for JSON fields.
This problem occurs when using an upload plugin that uses an iframe to do the upload with IE (tested on 9.0).
IE sets the header Accept: text/html, , application/xhtml+xml, */* and so when you reply with Content-type: application/json, it assumes it's the file (or at least that's the only explanation I could find on the web).
Thus, to circumvent that, you need to set Content-type: text/html or Content-type: text/plain.
I would recommend implementing this using an ActionFilter; instead of manually changing the content type, detect IE and a multipart POST and change the content-type accordingly.
Possibly you are not setting a correct mime type for your json content (for IE try text/plain)
See: What problems may using the MIME type application/json cause?
I was using this same uploader and had the same problem.
It has to do with the request headers sent. IE needs the request to have an accept header that indicates json.
xhr.setRequestHeader("Accept", "application/json, text/javascript, */*; q=0.01");
If you insert this after this line:
xhr.setRequestHeader("Content-Type", "application/octet-stream");
in the js file (mine is called fileuploader.js) then you should no longer have the problem, and don't need to indicate text/html in your return.
p.s.
I commented out the content-type line, but am no longer sure why. If just adding this the accept line does not work, try commenting out the content-type header as well.
Edit:
I looked at my file again, and it seems like also made another change.
Instead of the line:
xhr.send(file)
I put in:
var formData = new FormData();
formData.append("image", file);
xhr.send(formData);
This comes after the setrequesrheader line above.
I am not sure if this change will work for all uses, like multiple file upload. I only upload a single image for my use.

Categories

Resources