NodeJS HTTP GET returns empty body - ajax

Here's a NodeJS code snippet I'm debugging. The url is correct, and a GET request to it with Postman returns a 200 OK with the following headers. The response body is a valid JSON string.
Headers (arrows represent column divisors)
Accept-Ranges →bytes
Age →0
Cache-Control →max-age=300
Connection →keep-alive
Content-Encoding →gzip
Content-Length →255
Content-Type →application/json
Date →Tue, 24 Jan 2017 22:37:28 GMT
Expires →Tue, 24 Jan 2017 17:47:43 GMT
Last-Modified →Tue, 24 Jan 2017 01:03:08 GMT
Server →nginx
Vary →Accept-Encoding
Via →1.1 varnish
X-Cache →HIT
X-Cache-Hits →1
X-Served-By →cache-yul8926-YUL
X-Timer →S1485297448.259768,VS0,VE89
The problem:
I've discovered that res.on('data', function(chunk) { never gets called which causes body to remain empty.
When res.on('end', function() { is called body still has length = 0. Any ideas why the data callback is not getting called?
http.get(url, function(res) {
var body = '';
res.on('data', function(chunk) {
body += chunk;
});
res.on('end', function() {
var data = JSON.parse(body);
cb(data, undefined);
});
}).on('error', function(err) {
console.log("Something went wrong");
console.log(err);
});
Also worth nothing, cb is a callback function defined outside of this snippet.

After the lovely advice from jfriend00 I discovered that res.statusCode was 301 (Moved Permanently). Seems that the website was redirecting to the same URL but with https protocol instead of http.
When testing the REST API with Postman it did not mention the fact the request was redirected. Postman displayed a 200 OK response (???) According to the Postman Docs it will default to following redirects silently.
The solution:
I replaced all instances of http with https and it worked great.
https.get(url, function(res) {
var body = '';
res.on('data', function(chunk) {
body += chunk;
});
res.on('end', function() {
var data = JSON.parse(body);
cb(data, undefined);
});
}).on('error', function(err) {
console.log("Something went wrong");
console.log(err);
});

Related

Getting error when returning list from rest service admin-on-rest

I'm getting the following error on my first admin component.
uncaught at handleFetch TypeError: newRecords.reduce is not a function
When I attempt to query my rest-api. I'm using the majority of the supplied simple rest client with some additional security headers thrown in.
My response from my API is:
HTTP/1.1 200 OK
Transfer-Encoding: chunked
Content-Type: application/json; charset=utf-8
Content-Range: Account 0-0/1
Server: Kestrel
Access-Control-Allow-Origin: *
Access-Control-Expose-Headers: Content-Range
Request-Context: appId=cid-v1:9f32da6c-a0dd-445f-b59f-d5d01ee6c462
X-AA-Request-ID: ad76be2b-0a29-4179-8fab-6ac0b83e411b
X-SourceFiles: =?UTF-8?B?RTpcRGV2XEFBSHViXEFBLkh1Yi5TZXR0aW5ncy5TZXJ2aWNlXEFBLkh1Yi5TZXR0aW5ncy5TZXJ2aWNlXGFwaVx2MVxhY2NvdW50?=
X-Powered-By: ASP.NET
Date: Tue, 15 Aug 2017 02:56:56 GMT
The body of the response has:
{"data":[{"changeManagements":[],"serviceProfiles":[],"id":1,"login":"cuken","permissionLevel":9001,"note":"This is a dev test user"}],"totalItems":1}
EDIT
Here is the fetch.js file I modified from the simple rest client example:
import HttpError from './HttpError';
export const fetchJson = (url, options = {}) => {
const requestHeaders = options.headers || new Headers({
Accept: 'application/json',
'X-AA-ClientName': 'fc5f3712-64fc-4ca4-9e5f-d4b6edeb46d4',
'X-AA-ApiKey': '80b4ccbf-a741-42ad-aacc-50c4309de8e6',
});
if (!(options && options.body && options.body instanceof FormData)) {
requestHeaders.set('Content-Type', 'application/json');
}
if (options.user && options.user.authenticated && options.user.token) {
requestHeaders.set('Authorization', options.user.token);
}
return fetch(url, { ...options, headers: requestHeaders })
.then(response => response.text().then(text => ({
status: response.status,
statusText: response.statusText,
headers: response.headers,
body: text,
})))
.then(({ status, statusText, headers, body }) => {
let json;
try {
json = JSON.parse(body);
} catch (e) {
// not json, no big deal
}
if (status < 200 || status >= 300) {
return Promise.reject(new HttpError((json && json.message) || statusText, status));
}
return { status, headers, body, json };
});
};
export const queryParameters = data => Object.keys(data)
.map(key => [key, data[key]].map(encodeURIComponent).join('='))
.join('&');
The simple.js file is an exact copy from the repo.
What did I do wrong?
You need a dedicated auth client to handle the auth types and shoot the appropriate actions
https://marmelab.com/admin-on-rest/Admin.html#authclient
That's because your API response is not what the simpleRestClient expects:
It should only contains
[{"changeManagements":[],"serviceProfiles":[],"id":1,"login":"cuken","permissionLevel":9001,"note":"This is a dev test user"}]
No data nor totalItems keys. As stated in the documentation:
The simple REST client expects the API to include a Content-Range header in the response to GET_LIST calls. The value must be the total number of resources in the collection. This allows admin-on-rest to know how many pages of resources there are in total, and build the pagination controls.

Response headers in Angular interceptor

I have an interceptor for authentication.
I want to get a header out of the response when I get a 401 response error.
Interceptor is:
function ($httpProvider, fileUploadProvider) {
$httpProvider.interceptors.push(function($q, $localStorage) {
return {
'request': function(config) {
if ($localStorage.token) {
config.headers.Authorization = 'Bearer ' + $localStorage.token;
}
return config;
},
'responseError': function(response) {
if (response.status === 401) {
//$rootScope.$broadcast('unauthorized');
// WWW-Authenticate: Bearer error="invalid_token"
var authResult = response.headers('WWW-Authenticate');
if (authResult.indexOf("invalid_token")>-1) {
$localStorage.token = null;
$timeout(function(){
;
});
}
}
return response;
}
};
I want to get the WWW-Authenticate header from the response.
I can confirm the header is in the response of the web service call by looking at the network tab in Chrome developers tools. If I set a break point in the response handler function and then run console.log(response.headers()) in the console I get:
Object {}
undefined
How do I get to the response headers?
The responseError function receives rejection instead of response.
Therefore if you want to access response headers, what you need is like below.
'responseError': function(rejection) {
if (rejection.status === 401) {
console.log(rejection.config.headers);
}
}
I hope this would help you. :)
Although I know this is not answer and should post as comment, I post it here to use screen capture image.
I tried to get a response header with my test enviroment like below.
nodejs server
res.setHeader('WWW-Authenticate', 'invalid_token');
res.status(401).send();
angularjs
'responseError': function(rejection) {
if (rejection.status === 401) {
console.log(rejection.headers('WWW-Authenticate'));
}
}
Chrome dev tool screen capture
As you can see, I could get the response header correctly.
Therefore I think that there seems to be some problem in your server code where you set a response header.
Would you like to show us your chrome dev tool screen capture and your server code where you set the response header?

Socket.IO: 400 Bad Request

I'm trying to make a connection to a node server from a page served by an APACHE server but I'm running into issues with the connection. I was getting cross domain errors until I set origin to allow all but now I'm getting a 400 bad request error.
server
var http = require('http');
var io = require('socket.io');
var server = http.createServer(function(request, response){
console.log('Connection');
response.writeHead(200, {'Content-Type': 'text/html'});
//response.write('hello world');
response.end();
});
server.listen(8001);
io.listen(server);
var socket = io.listen(server);
socket.set('origins', '*');
socket.on('connection', function() {
console.log('mooo');
});
client
<script src="https://cdn.socket.io/socket.io-1.3.5.js"></script>
<script src = "http://localhost:8001"> </script>
<script>
var socket = io.connect('http://localhost:8001');
</script>
error:
GET XHR http://localhost:8001/socket.io/ [HTTP/1.1 400 Bad Request 2ms]
Your code is running fine without the following code but Im not running on apache. I have got the output "hello world" in browser (http://localhost:8001/).
var socket = io.listen(server);
io.set('origins', '*');
io.on('connection', function() {
console.log('mooo');
});
How are your accessing the page because 404 is something that your page can not be located by the request.

IE striping headers from HTTP POST request to S3

I'm doing straight-to-S3 multipart file upload via AJAX. Everything works fine under all browsers but IE.
S3 requires an Authorization HTTP header in each POST request which contains the signature of the file slice being uploaded.
It appears IE strips out this header from the request, yielding a 403 response.
What's more funny is that IE does not strip another custom S3 header: x-amz-date.
Any idea how I can force the 'Authorization' header in?
As requested, here is my code :
initiateUpload: function() {
var response = this.sign({method:'POST', path: this.key + '?uploads'});
this.request({
method: 'POST',
url: response.url,
headers: {
'x-amz-date': response.date,
'Authorization': response.signature
},
onLoad: this.uploadParts.bind(this)
});
},
request: function(params){
var xhr = new XMLHttpRequest();
if (params.onLoad) xhr.addEventListener("load", params.onLoad, false);
if (params.onUploadStart) xhr.upload.onloadstart = params.onUploadStart;
if (params.onUploadProgress) xhr.upload.onprogress = params.onUploadProgress;
xhr.open(params.method, params.url, true);
for (h in params.headers)
xhr.setRequestHeader(h, params.headers[h]);
xhr.send(params.body);
},

Ajax file upload in node.js

Want to upload a file using ajax for this using this uploader
http://valums.com/ajax-upload/
and in node.js write this code which is working with normal file upload without ajax .
console.log("request " + sys.inspect(req.headers));
req.on('data', function(chunk) {
console.log("Received body data:");
// console.log(chunk.toString());
});
var form = new formidable.IncomingForm();
form.parse(req, function(err,fields, files) {
console.log('in if condition'+sys.inspect({fields: fields, files: files}));
fs.writeFile("upload/"+files.upload.name, files.upload,'utf8', function (err) {
if (err) throw err;
console.log('It\'s saved!');
client.putFile("upload/"+files.upload.name, files.upload.name, function(err, res){
if (err) throw err;
if (200 == res.statusCode) {
console.log('saved to s3');
httpres.writeHead(200, {'content-type': 'text/plain'});
httpres.write('received 1upload:\n\n');
httpres.end();
}
});
});
});
But this is giving error ?
request { host: 'myhost:8001',
'user-agent': 'Mozilla/5.0 (Windows NT 5.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1',
accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'accept-language': 'en-us,en;q=0.5',
'accept-encoding': 'gzip, deflate',
'accept-charset': 'ISO-8859-1,utf-8;q=0.7,*;q=0.7',
'keep-alive': '115',
connection: 'keep-alive',
origin: 'http://myhost',
'access-control-request-method': 'POST',
'access-control-request-headers': 'content-type' }
events.js:45
throw arguments[1]; // Unhandled 'error' event
^
Error: bad content-type header, no content-type
at IncomingForm._parseContentType (/usr/local/lib/node/.npm/formidable/1.0.0/package/lib/formidable/incoming_form.js:196:17)
at IncomingForm.writeHeaders (/usr/local/lib/node/.npm/formidable/1.0.0/package/lib/formidable/incoming_form.js:109:8)
at IncomingForm.parse (/usr/local/lib/node/.npm/formidable/1.0.0/package/lib/formidable/incoming_form.js:65:8)
at Server.<anonymous> (/home/myfolder/myfolder/newcontentserver.js:29:18)
at Server.emit (events.js:67:17)
at HTTPParser.onIncoming (http.js:1108:12)
at HTTPParser.onHeadersComplete (http.js:108:31)
at Socket.ondata (http.js:1007:22)
at Socket._onReadable (net.js:678:27)
at IOWatcher.onReadable [as callback] (net.js:177:10)
I think problem is the content-type is not set in the headers By ajax file upload .thats why this error is coming how can i set the header in this uploader , or how can i make a file in node.js server by incoming data.
As it is using the xhr so i think i can't use the formidable.incomingform() what should i use?
Looking at the latest fileuploader.js source code on github he does set the content type
xhr.setRequestHeader("Content-Type", "application/octet-stream");
I believe your problem is elsewhere.

Resources