Downloading a file in response to POST request? - http

I'm trying to create an API endpoint that accepts several files (that's why I need POST request, not GET request) and responds with another file. I want browser to present a "save as..." dialog (or just start downloading).
Here's a demo code that doesn't work (Flask):
#app.route('/api', methods=['POST'])
def api():
return send_file('./sample.txt', as_attachment=True)
I can see proper response headers, but nothing happens in the browser:
HTTP/1.0 200 OK
Content-Disposition: attachment; filename=sample.txt
Content-Length: 612
Content-Type: text/plain; charset=utf-8
If I remove methods=['POST'] from endpoint and issue a GET request to it, it works fine, the browser asks if I want to save this file.
What am I doing wrong or it's just how things are (Content-Disposition ignored for POST responses?)

Seems browser shows pop-up for the download, only for the GET requests. But there is a way to show it from client side. Something like this:
document.getElementById('download').addEventListener('click', function () {
var content = document.getElementById('content').value;
var request = new XMLHttpRequest();
request.open('POST', '/api', true);
request.setRequestHeader('Content-Type', 'text/plain; charset=UTF-8');
request.responseType = 'blob';
request.onload = function() {
if(request.status === 200) {
var filename = 'sample.txt';
// The actual download
var blob = new Blob([request.response], { type: 'text/plain' });
var link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = filename;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
// some error handling should be done here...
};
request.send('content=' + content);
});
More details in this question and in this post

Related

How do I set headers on Flutter/Dart http Request object?

I need a way to set the headers of the dart http Request object to application/JSON.
I want to build a Request object to send to my backend API. I set the body to my JSON object, but when it gets sent, it defaults the headers to text/html instead of application/json.
I have tried using the built-in method
http.post(url,dynamic body);
but unfortunately this method places the body in the parameters of the URL and I need it in the actual body of the request.
So instead I built an http Request object, and manually set the URL and body but like I said, it sets the headers to text/html.
I have read the docs for https://pub.dev/documentation/http/latest/http/Request-class.html, but unfortunately, I haven't found a way to set the headers.
postRequest(uri) async {
Uri url = Uri.tryParse("https://ptsv2.com/t/umt4a-1569012506/post");
http.Request request = new http.Request("post", url);
request.body = '{mediaItemID: 04b568fa, uri: https://www.google.com}';
var letsGo = await request.send();
print(letsGo.statusCode);
}
Much thanks for any possible solutions!
Ps. this is my first ask on Stack Overflow so I apologize if I made any errors in posting.
Solved!
postRequest(uri) async {
Uri url = Uri.tryParse("https://ptsv2.com/t/umt4a-1569012506/post");
http.Request request = new http.Request("post", url);
request.headers.clear();
request.headers.addAll({"content-type":"application/json; charset=utf-8"});
request.body = '{mediaItemID: 04b568fa, uri: https://www.google.com}';
var letsGo = await request.send();
print(letsGo.statusCode);
}
I was having some issues with the Request object default setting the encoding.
By manually specifying utf-8, the server I am contacting accepts it.
for the post or get any request you can Add Header like this -
var permAddUrl = 'your requested url';
var bodyParameters = {
'Email': email,
'MobileNo': mobileNumber,
};
await http.post(
requesturl,
headers: { 'Content-Type': 'application/x-www-form-urlencoded',
"Authorization":"$token",
},
body: bodyParameters,).then((response) {
var data = json.encode(response.body);
print(data);
setState(() {
if(response.statusCode == 200){
//var statesList = data['data'];
UtilAction.showSnackBar(context, " Details Submitted Successfully");
}
});
});

How to get custom response header in angular 2?

I am new to angular 2 and currently working with angular 2.2.1 in which I am successfully able to post request and get success response however when I try to get Authorization header from response I always get null whether I am able to get Content-Type header. Below is my solution so far.
service.ts login method:
login(model: LoginModel) {
let requestUrl = '/someurl';
let requestPayload = JSON.stringify(model);
let headers = this.getHeaders(false); // ... Set all required headers
let options = new RequestOptions({ headers: headers }); // Create a request option
return this.http.post(requestUrl, requestPayload, options) // ...using post request
//.map((res: Response)) // ...and calling .json() on the response to return data
.subscribe((res: Response) => {
var payload = res.json();
var authorization = res.headers.get('Authorization');
var contentType = res.headers.get('Content-Type');
console.log(payload, contentType, authorization)
});
}
Header Helper
getHeaders(isSecureAPI: boolean) {
let headers = new Headers({ 'Content-Type': 'application/json', 'Accept': 'application/json' });
if (isSecureAPI) {
headers.append('Authorization', 'GetFromSession');
headers.append('X-UserID', 'GetFromSession');
}
return headers;
}
Fiddler track:
Angular Console Output
So anyone can guide me what I am possibly doing wrong?
Header was allowed but not exposed on CORS server however adding headers.add("Access-Control-Expose-Headers", "Authorization, X-Custom"); on server did the job :)
I've been trying to find a solution and came across this
Let's say I'm using the Microsoft Cors WebAPI 2 Nuget package, and I have the following global configuration in my WebApiConfig.cs:
...
var corsAttr = new EnableCorsAttribute("http://localhost:4200", "*", "*");
config.EnableCors(corsAttr);
...
The EnableCorsAttribute constructor accepts a 4th string parameter to globally allow any additional headers:
var corsAttr = new EnableCorsAttribute("http://localhost:4200", "*", "*", "X-Foo, X-Bar, X-Baz");

request body on Server side is an empty array, express node.js REST

So I've searched all over for the answer, can't seem to find one
I'm making a nodejs app, and at one point I want to POST data in the form of a JSON to my server. Here is what I have in my 'users.js' on the server:
/** Updates the array with the new user information **/
exports.addUser = function(req, res) {
var user = req.body;
var userDB = findByEmail(user.email);
if(userDB == -1){
//New user - send back user information
users.push(user);
res.send(JSON.stringify(user));
Whenever I check on Chrome - I see that although I am SENDING the corrent information, the response is just {}
Here's what I have on the client.js
var user = {email:userEmail,username:userUsername,password:userPassword};
request = new XMLHttpRequest();
if (request)
{
request.open("POST","users");
request.onreadystatechange = function()
{
if (request.readyState == 4 &&
request.status == 200){
result = JSON.parse(request.responseText);
if(result == 0)
{
//Result came back as 0 - Old User, wrong password
}
if(result == 1){
//Result came back as 1 - Correct password, old User
}
if(result.email == userEmail){
//Result came back as -1 - New User
}
}
}
request.send(JSON.stringify(user));
}
Now everything here I think is correct - because I see the HTTP request coming out good.
However it appears in the 'payload' part of the request - is this normal?
Here is my requires on server.js -
var express = require('express');
var questions = require('./Quotes');
var scoreboard = require('./scoreboard');
var users = require('./users');
var app = express();//.createServer();
app.configure(function () {
app.use(express.logger('dev'));
app.use(express.bodyParser());//it will parse json request bodies (as well as others), and place the result in req.body:
});
app.post('/users',users.addUser);
Finally here is what the Chrome shows when I test it -
I forgot to add - this is how the request looks on Chrome -
Accept:*/*
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8
Connection:keep-alive
Content-Length:70
Content-Type:application/xml
Host:whosaidit.eu01.aws.af.cm
Origin:http://whosaidit.eu01.aws.af.cm
Referer:http://whosaidit.eu01.aws.af.cm/
User-Agent:Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.93 Safari/537.36
Request Payloadview source
{email:oreporan#gmail.com, username:orepor, password:yotamp}
email: "john#gmail.com"
password: "password"
username: "john123"
Please help!
Thanks
There's a couple of things I'm noticing:
Even though you are encoding your client side data to JSON, you're not telling the server that it's JSON that you are sending to it. Before you send your request, set the content-type:
request.setRequestHeader('content-type', 'application/json');
request.send(...);
How is findByEmail() implemented? If it queries a database, the chances are that it's implemented asynchronously, meaning that you cannot expect it to return a useful return code.
This piece of code is confusing:
if (userDB == -1) {
users.push(user); // what is 'users'? what's the use of this code?
res.send(JSON.stringify(user)); // you send back an object, but in your
// client side code you are expecting a
// number: "if (result == 0)"
}

XDomainRequest in IE is giving Access is Denied error

This is the code I am using is as follows down below:
I am using IE9 and am unable to see the request being sent in the Network tab. I do have Access-Control headers set in the JSP as:
<% response.setHeader("Access-Control-Allow-Origin", "*");%>
Code to get the AJAX HTML Content from the JSP:
if ($.browser.msie && window.XDomainRequest) {
var xdr = new window.XDomainRequest();
xdr.open("GET", "http://dev01.org:11110/crs/qw/qw.jsp?&_=" + Math.random());
xdr.contentType = "text/plain";
xdr.timeout = 5000;
xdr.onerror = function () {
console.log('we have an error!');
}
xdr.onprogress = function () {
console.log('this sucks!');
};
xdr.ontimeout = function () {
console.log('it timed out!');
};
xdr.onopen = function () {
console.log('we open the xdomainrequest');
};
xdr.onload = function() {
alert(xdr.responseText);
};
xdr.send(null);
} else { ...... }
I am getting a Access is Denied Error. Any help would be much appreciated!
Requests must be targeted to the same scheme as the hosting page
In your example you are doing request to:
http://dev01 ...
And you should do this from HTTP protocol.
For example:
If your site, where js script is located: http://dev.org
You can do this:
xhr = new XDomainRequest();
xhr.open("GET", "http://dev01.org?p=1");
but this throws "Access denied":
xhr = new XDomainRequest();
xhr.open("GET", "https://dev01.org?p=1");
My experience with XDomainRequest is that it doesn't respect Access-Control-Allow-Origin: *. Instead, you must specify the domain. This can be obtained from the HTTP_REFERER header if you need to dynamically generate it, or if you are only expecting requests from one domain you can set it manually. This article might help.
<% response.setHeader("Access-Control-Allow-Origin", "http://dev01.org");%>

Extracting POST data with Express

I've read node.js Extracting POST data.
But here's my problem, how to extract POST data with Express when I received a HTTP request looking like this?
POST /messages HTTP/1.1
Host: localhost:3000
Connection: keep-alive
Content-Length: 9
User-Agent: Mozilla/5.0 (X11; Linux i686) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.52 Safari/536.5
Content-Type: application/xml
Accept: */*
Accept-Encoding: gzip,deflate,sdch
Accept-Language: zh-TW,zh;q=0.8,en-US;q=0.6,en;q=0.4 Accept-Charset: UTF-8,*;q=0.5
msg=hello
I can't seem to get the msg=hello key-value pair out of the body with Express.
I've tried all of these methods req.header() req.param() req.query() req.body but they seem to be empty.
How to get the body's content?
app.post('/messages', function (req, res) {
req.??
});
Your problem is bodyParser does not handle 'application/xml', I solved this mainly by reading this post: https://groups.google.com/forum/?fromgroups=#!topic/express-js/6zAebaDY6ug
You need to write your own parser, I've published the below with more detail to github:
https://github.com/brandid/express-xmlBodyParser
var utils = require('express/node_modules/connect/lib/utils', fs = require('fs'), xml2js = require('xml2js');
function xmlBodyParser(req, res, next) {
if (req._body) return next();
req.body = req.body || {};
// ignore GET
if ('GET' == req.method || 'HEAD' == req.method) return next();
// check Content-Type
if ('text/xml' != utils.mime(req)) return next();
// flag as parsed
req._body = true;
// parse
var buf = '';
req.setEncoding('utf8');
req.on('data', function(chunk){ buf += chunk });
req.on('end', function(){
parser.parseString(buf, function(err, json) {
if (err) {
err.status = 400;
next(err);
} else {
req.body = json;
next();
}
});
});
}
then use it with
app.use (xmlBodyParser);
If you have this in the config:
app.use(express.bodyParser());
And this in your view:
form(name='test',method='post',action='/messages')
input(name='msg')
Then this should work:
app.post('/messages', function (req, res) {
console.log(req.body.msg);
//if it's a parameter then this will work
console.log(req.params.msg)
});
I believe you need to configure express to use the bodyParser middleware.
app.use(express.bodyParser());
See the express documentation.
It says:
For example we can POST some json, and echo the json back using the bodyParser middleware which will parse json request bodies (as well as others), and place the result in req.body
req.body() should now return the expected post body.
I hope this helps!
It's POSSIBLE (not sure what it depends on, but it happened to me once, it might be the bodyParser) that the request body is formatted in such a way that your JSON data is ITSELF being treated as a key in a key-value pair, with a blank corresponding value. What's worked for me in this situation was to extract the JSON object first and then proceed as normal:
var value;
for (var item in req.body)
{
var jObject = JSON.parse(item);
if (jObject.valueYouWant != undefined)
{
value = jObject.valueYouWant;
}
}
This is probably pretty suboptimal, but if nothing else works (I tried for ages trying to find a better way and found none) this might work for you.
You are posting xml as I can see, the answers you got were based on JSON input. If you want the content of your xml displayed, process the raw request :
app.post('/processXml',function (req, res)
{
var thebody = '';
req.on('data' , function(chunk)
{
thebody += chunk;
}).on('end', function()
{
console.log("body:", thebody);
});
});
As an example using curl as your postman:
curl -d '<myxml prop1="white" prop2="red">this is great</myxml>' -H
"Content-type: application/xml" -X POST
http://localhost:3000/processXml
Outputting:
'<myxml prop1="white" prop2="red">this is great</myxml>'
Make sure your body-parser middleware doesn't get in the way: body-parser-xml processes your request object on the fly to a json object, after which you cannot process your raw request anymore. (And you can guess who was stuck several hours after this...)

Resources