node.js, express and different ports - node.js

I've been playing with node.js and then came across the express framework. I can't seem to get it to work when different ports are being used.
I have my ajax on http://localhost:8888 which is a MAMP server I'm running on my Mac.
$.ajax({
url: "http://localhost:1337/",
type: "GET",
dataType: "json",
data: { },
contentType: "application/json",
cache: false,
timeout: 5000,
success: function(data) {
alert(data);
},
error: function(jqXHR, textStatus, errorThrown) {
alert('error ' + textStatus + " " + errorThrown);
}
});
As you can see my node.js server is running on http://localhost:1337/. As a result nothing is getting returned and it's throwing an error.
Is there a way around this?
Thanks
Ben

The problem you have is that you are trying to make a cross-origin request and that's not allowed by browsers (yes, the same hostname with a different port counts as a different origin for this purpose). You have three options here:
1. Proxy the request.
Do this one if you can. Write some code that runs on the :8888 server
that proxies requests to the 1337 one. You can also do this by
sticking a proxy in front of both of them, something like Nginx is
pretty good at this and easy to set up
2. Use CORS (Cross Origin Resource Sharing)
See: http://en.wikipedia.org/wiki/Cross-origin_resource_sharing and https://developer.mozilla.org/en/http_access_control
This means adding some headers to your responses to tell the browser that cross-origin requests are ok here. In your Express server add middleware like this:
function enableCORSMiddleware (req,res,next) {
// You could use * instead of the url below to allow any origin,
// but be careful, you're opening yourself up to all sorts of things!
res.setHeader('Access-Control-Allow-Origin', "http://localhost:8888");
next()
}
server.use(enableCORSMiddleware);
3. Use JSONP
This is a trick where you encode your "AJAX" response as Javascript code. Then you ask the browser to load that code, the browser will happily load scripts cross-origin so this gets round the cross-origin issue. It also lets anyone else get round it as well though, so be sure that's what you want!
On the server side you need wrap your response in a Javascript function call, express can do this for automatically if you enable the "jsonp callback" option like this:
server.enable("jsonp callback");
Then send your response using the "json()" method of response:
server.get("/ajax", function(req, res) {
res.json({foo: "bar"});
});
On the client side you can enanble JSONP in jQuery just by changing "json" to "jsonp" in the dataType option:
dataType: "jsonp",

Related

how do I allow a google app engine node js script to call cross domain?

I am new to GAE / NODEJS. There is plenty of advice to enable calls hosted by GAE to be called cross domain, but I am having trouble getting my node js app to call another domains API. Is there something I need to do to get GAE to allow cross domain calls? My code is:
app.get('/listProducts', (req, res) => {
request.get('https://[cross domain]/api/2.0/products', function (error, response, body) {
console.log('error:', error); // Print the error if one occurred
console.log('statusCode:', response && response.statusCode); // Print the response status code if a response was received
console.log('body:', body); // Print the HTML for the Google homepage.
}).auth(null, null, true, '[key goes here]');
You can allow configuring your app.yaml file or setting in your http header.
Here the doc (looking for CORS Support )
Follow the example:
You could have a game app mygame.appspot.com that accesses assets
hosted by myassets.appspot.com. However, if mygame attempts to
make a JavaScript XMLHttpRequest to myassets, it will not succeed
unless the handler for myassets returns an
Access-Control-Allow-Origin: response header containing the value
http://mygame.appspot.com.
Here is how you would make your static file handler return that required response header value:
handlers:
- url: /images
static_dir: static/images
http_headers:
Access-Control-Allow-Origin: http://mygame.appspot.com
# ...
Note: if you wanted to allow everyone to access your assets, you could use the wildcard '*', instead of http://mygame.appspot.com.
was doing newbie - i should have returned a response code, eg response.status(200).send("ok").end();

"Fetch failed loading" - fetch works in Postman but fails in Chrome & Safari

Update: Fixed. It looks like the request was coming back as a 503 (as it should), then my app refreshed and displayed the non-error message: "Fetch failed loading". I just wasn't seeing the response because of the refresh.
I am not able to make a fetch request from my locally-hosted Create-React-App to my Heroku-hosted Node server.
My Node server has CORS enabled. If I make a POST request via Postman, I get an appropriate response (503, because currently there is no database hooked up, so the data is not being saved. If I should be sending back a different response, let me know). My Postman request has 'application/json' as the content-type, no authorization, and a body of { "rating": "5", "zipcode": "0" }.
However, when I make a POST request from my React app, I get a message in my console: "Fetch failed loading: OPTIONS "https://shielded-gorge-69158.herokuapp.com/feedback"." There is no associated error, only the message. There is no information about the request in my Network panel.
The fetch request works when I do it locally, from localhost:3000 (my app) to localhost:5000 (my server). It only fails when I try to make the request to the (otherwise identical) server hosted on Heroku.
This is what the fetch request looks like:
return fetch('https://shielded-gorge-69158.herokuapp.com/feedback', {
method: 'POST',
headers: {
'Content-type': 'application/json'
},
body: JSON.stringify({ rating: userRating, zipcode: userZip })
}).then(res => {
if (!res.ok) {
throw new Error('Error:', res.statusText);
}
return res;
}).catch(err => console.error(err));
Edit: I'm continuing to research and it seems like Postman shouldn't/doesn't make preflight requests (https://github.com/postmanlabs/postman-app-support/issues/2845). So perhaps that is the issue — but why would the request be working when my server is local, but not when it is hosted on Heroku?
use 'Content-Type' instead of 'Content-type'.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Simple_requests
https://fetch.spec.whatwg.org/#cors-safelisted-request-header
Explanation: when you use incorrect case then it is considered as a custom header and hence, a preflight request is sent in such cases. Now if OPTIONS request is implemented on server with correct cors spec then next POST will be sent, else it wont be sent and request will fail. More on this in above links.

Android Browser does not handle cross domain ajax request properly

I wrote HTML/JS application which works offline - it's put on SD card and is run using default 4.1 Android Browser.
I'm making the Ajax request using jQuery to host in the internet. Since i'm running it from local filesystem it's obviously a cross domain request. The server has a mechanism based on header manipulation which enables such CD requests. Piece of troubling code:
$.ajax({
type: "POST",
crossDomain: true,
data : formData,
cache: false,
url: "http://someurlwhichhandlescrossdomain.com",
success: function(data){
alert("hurrayy!");
},
error: function(xhr, ajaxOptions, thrownError) {
alert("bah :/");
alert(xhr.status);
alert(thrownError);
}
});
The problem is that the error function is always executed, although data is being sent correctly and the server registered the request properly. The xhr.status is always 0, and thrownError is empty.
The same piece of code works correctly on Chrome on Desktop (alerts "hurray").
Currently i use a workaround based on navigator.onLine, and if the value is true i assume that data has been sent correctly to the server (as i don't need to read anything from server). However this solution is bad because if the connection is working, but the server is not, i can't handle it.
Any ideas?
Thanks,
Karol

nodejs configuration httpd.conf

I'm used to apache and putting configuration items in httpd.conf
Where do these types of configurations go in a node environment. For example, I want to make sure that only GET, POST, and PUT are accepted and Head and Trace are not accepted. Where does a config like that go?
Additional things like Cache-Control and limiting request and response sizes.
Node.js is just a JS framework with a system API. Technically, you could reimplement Apache HTTP Server in Node.js, mimicking its behaviour and its configuration structure. But would you?
I believe you are using Node.js' HTTP module. Look at the docs: there's no way to read configuration from a file. The server is programmatically created using http.createServer. You provide a callback that listens to requests. This callback provides an http.IncomingMessage parameter (first parameter) which contains everything you need.
Here's an example:
// load the module
var http = require('http');
// create the HTTP server
var server = http.createServer(function(request, response) {
// use the "request" object to know everything about the request
console.log('got request!');
// method ('GET', 'POST', 'PUT, etc.):
console.log('HTTP method: ' + request.method);
// URL:
console.log('HTTP URL: ' + request.url);
// headers:
console.log('HTTP headers follow:');
console.log(request.headers);
// client address:
console.log('client address: ' + request.socket.address().address);
});
// listen on port 8000
server.listen(8000);
If you really want a configuration file, you will have to forge it yourself. I suggest creating a JSON configuration file as this can be turned directly into a JS object using JSON.parse(). Then just use your configuration object programmatically to achieve what you want.

JSONP request working cross-domain, but can't figure out origin

I'm trying out a JSONP call. I have a NodeJs app in server 1, under domain domain1.com looking like this:
server.get('/api/testjsonp', function(req, res) {
var clientId = req.param('clientId');
res.header('Content-Type', 'application/json');
res.header('Charset', 'utf-8')
res.send(req.query.callback + '({"something": "rather", "more": "fun",
"sourceDomain": "' + req.headers.origin + '"' + ',"clientId":"' + clientId +
'"});');
});
In another server (server 2) and under a different domain (domain2.com), I have created a test html page with a call like this:
var data = { clientId : 1234567890 };
$.ajax({
dataType: 'jsonp',
data: data,
jsonp: 'callback',
url: 'https://domain1.com/api/testjsonp?callback=1',
success: function(data) {
alert('success');
},
error: function(err){
alert('ERROR');
console.log(err);
}
});
I have 2 problems here:
1) Why is this working? Isn't it a cross-domain call and therefore I'd need to implement the ALLOW-ORIGIN headers stuff? I'm following this example:
http://css.dzone.com/articles/ajax-requests-other-domains
http://benbuckman.net/tech/12/04/cracking-cross-domainallow-origin-nut
2) In the server, I can't figure out which domain is making the call, req.headers.origin is always undefined. I'd like to be able to know which domain is calling, to prevent unwanted calls. Alternative I could check for the calling IP, any idea how?
Many thanks
Why is this working? Isn't it a cross-domain call and therefore I'd need to implement the ALLOW-ORIGIN headers stuff? I
Are far as the browser is concerned, you aren't directly reading data from a different origin. You are loading a JavaScript program from another origin (and it happens to have some data bundled in it).
In the server, I can't figure out which domain is making the call, req.headers.origin is always undefined. I'd like to be able to know which domain is calling, to prevent unwanted calls.
The URL of the referring page is stored in the Referer header, not the Origin header. It is, however, optional and won't be sent under many circumstances.
If you want to limit access to the data to certain sites, then you can't use JSON-P. Use plain JSON and CORS instead.
Alternative I could check for the calling IP, any idea how?
That would give you the address of the client, not the server that directed the client to you.

Resources