Express.js Find URL of client consuming REST API - node.js

Lets say, I have a server running at: https://example.com
The code in server:
const express = require("express");
const app = express();
app.get('/',(req, res)=>{
let data = {'Hello':'World'}
res.json(data);
});
app.post('/',(req, res)=>{
let name = req.body.name;
let email = req.body.email;
res.json({name, email});
});
app.listen(3000);
Now, there is a client: https://website.com, trying to access server response by making a GET and POST request. (No API key is required)
How can the server find the web address of the client?
In this example, I want the server (example.com) to determine the client's URL (website.com) and save it in the database. req.hostname() is not giving the desired output..

req.hostname is what you're looking for.
Update:
After re-reading your question, I think what you want is identifying cross-origin requests, you would instead use the Origin header.
var origin = req.get('origin');
Note that some cross-origin requests require validation through a "preflight" request:
req.options('/route', function (req, res) {
var origin = req.get('origin');
// ...
});

Related

Can't fetch the authorization code after the redirect url

I am working on Salesforce and Slack integration. And I don't know much about javascript and its related technologies. Could you please look into the code and let me know whats missing?
// Import express and request moduless
var express = require('express');
var request = require('request');
var url = require('url');
var clientId = '****';
var clientSecret = '****';
var SF_LOGIN_URL = "http://login.salesforce.com";
var SF_CLIENT_ID = "****";
// We define the port we want to listen to. Logically this has to be the same port than we specified on ngrok.
const PORT=4390;
// Instantiates Express and assigns our app variable to it
var app = express();
app.enable('trust proxy');
//var server = http.createServer(app);
//Lets start our server
app.listen(PORT, function () {
//Callback triggered when server is successfully listening.
console.log("Example app listening on port " + PORT);
});
var bodyParser = require('body-parser');
app.use(bodyParser.json()); // support json encoded bodies
app.use(bodyParser.urlencoded({ extended: true })); // support encoded bodies
// Route the endpoint that our slash command will point to and send back a simple response to indicate that ngrok is working
app.post('/oauth', function(req, res) {
oauth(req, res);
});
function oauth(req, res){
res.redirect(200, `${SF_LOGIN_URL}/services/oauth2/authorize?response_type=code&client_id=${SF_CLIENT_ID}&redirect_uri=****/oauth&display=touch}`);
console.log(url.location.href);
}
It looks to me like you're redirecting an authorization request to Salesforce, and asking Salesforce.com (SFDC) to redirect it back to ****/oauth (from the redirect_uri= query parameter to the SFDC URL.
Are you hoping it will get redirected back to your own /oauth endpoint?
If so, it's possible SFDC is redirecting it with a GET operation rather than a POST operation. Be aware that the parameters to a GET show up in req.params rather than req.body.
Try implementing a get() handler to see if you get something workable.
app.get('/oauth', function(req, res) {
console.log ('GET /oauth', req.params)
/* do something here */
});

Node Express Cors issue

I cant figure why the cors express middleware wont work. cors, express, and ejs are all saved in package.json. The app works fine if I add corsanywhere proxy on the front end but id like to work around this on the server side. any help much appreciated I've been stuck on this.
the api is in the get View/index path
the error is:
Access to fetch at 'https://api.darksky.net/forecast/' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
const express = require('express');
const app = express();
const ejs = require('ejs');
const cors = require('cors');
const PORT = process.env.PORT || 3000;
// app.use((req, res, next) => {
// res.header('Access-Control-Allow-Origin', '*')
// res.header('Access-Control-Allow-Headers', 'Origin', 'X-Requested-With')
// next();
// });
app.use(cors());
app.use(express.static(__dirname + '/Public'));
app.set('view engine', 'ejs');
app.get('/', cors(), (req, res) => {
res.render(__dirname + '/Views/index')
});
app.listen(PORT, () => {
console.log(`server is listening on ${PORT}`)
});
client side:
it works with the ${proxy} in there but id like to get rid of that
if(navigator.geolocation){
navigator.geolocation.getCurrentPosition(position => {
long = position.coords.longitude;
lat = position.coords.latitude;
var proxy = 'https://cors-anywhere.herokuapp.com/'
var api = `${proxy}https://api.darksky.net/forecast/042750f3abefefdfe2c9d43cf33ce576/${lat},${long}`;
fetch(api)
.then(response => {
return response.json();
})
.then(data => {
let {temperature, summary, icon,} = data.currently;
temperatureDegree.textContent = Math.floor(temperature);
temperatureDescription.textContent = summary;
locationTimezone.textContent = data.timezone;
setIcons(icon, document.querySelector('.icon'
w
``````
So, if you're trying to access some other service https://api.darksky.net/forecast/ (that you don't control) from your web page, then there is nothing you can do to make CORs work for that. It's up to the api.darksky.net server to decide if CORs is allowed or not. You can't change that.
You could make a request from your web page to your server to ask it to get some data from api.darksky.net for you and then return it back to your webpage (working as a simple proxy). Your server is not subject to any CORs limitations when accessing api.darksky.net. Only browsers are limited by CORs.
And, as you've found, you can also use a proxy service that enables CORs and fetches data for you.
Let's suppose you want to proxy the parts of the darksky API, you could do something simple like this:
const express = require('express');
const app = express();
const request = require('request');
const apiRouter = express.Router();
// maps /api/forecast/whatever to http://api.darksky.net/forecast/developerKey/whatever
// and pipes the response back
const apiKey = "yourAPIKeyHere";
apiRouter.get("/*", (req, res, next) => {
// parse out action and params
// from an incoming URL of /api/forecast/42.3601,-71.0589
// the /api will be the root of the router (so not in the URL here)
// "forecast" will be the action
// "42.3601,-71.0589" will be the params
let parts = req.path.slice(1).split("/"); // split into path segments, skipping leading /
let action = parts[0]; // take first path segment as the action
let params = parts.slice(1).join("/"); // take everything else for params
request({
uri: `https://api.darksky.net/${action}/${apiKey}/${params}`,
method: "get"
}).pipe(res);
});
app.use("/api", apiRouter);
app.listen(80);
Now, when you send this server, this request:
/api/forecast/42.3601,-71.0589
it will request:
https://api.darksky.net/forecast/yourAPIKeyHere/42.3601,-71.0589
and pipe the result back to the caller. I ran this test app and it worked for me. While I didn't see anything other than forecast URLs in the darksky.net API, it would work for anything of the format /api/someAction/someParams.
Note, you probably do NOT want to enable CORS on your server because you don't want other people's web pages to be able to use your proxy. And, since you're just sending requests to your own server now, you don't need CORS to be able to do that.

request header can't get cookie when using res.cookie of Express 4.x

i just want to try basic methods to set cookie and show in request head.
front-end is just a basic html form with username and password text input, use POST method to transfer data.
below is code based on express.
server just receive req.body, then set it as cookie with domain: localhost:1338/base
cookieRouter.js:
var express = require('express');
var bodyParser = require('body-parser');
var cookieParser = require('cookie-parser');
var router = express.Router();
router.use(bodyParser.urlencoded({ extended: false }));
router.use(cookieParser());
router.get('/', function (req, res) {
res.send('this is a router base page!');
});
router.get('/index1.html', function (req, res) {
res.sendFile(__dirname + '/index1.html');
});
router.post('/index1.html', function (req, res) {
res.cookie('name', req.body, { domain: 'localhost:1338', path: '/base' });
res.send(req.body);
});
module.exports = router;
app.js
var express = require('express');
var app = express();
var cookieRouter = require('./cookieRouter.js');
app.get('/', function (req, res) {
res.send('this is home page!');
});
app.use('/base', cookieRouter);
app.listen(1338);
after run app.js, request header has set-cookie value obviously. but can't get it into request header, and req.cookies is empty object {}, even after refreshing the web.
but if i just use simplest demo, it can work, for instance:
router.get('/', function (req, res) {
res.cookie('name', 'test');
});
one more thing, i feel the trouble with express is that only one res.send(), res.redirect()... can be sent as by default it will add head automatically, otherwise, it will come up with error: Can't set headers after they are sent.
someone said add return can solve this problem, but i failed, so want to how how to add, can anyone give an complete demo?
The cookie is missing because the domain attribute is incorrect -- 'localhost:1338' need to be changed to 'localhost'. Port information should not be included in domain.
Yes, according to the Network panel of browser dev tool, there is a Set-Cookie response header (as the screenshot displayed). However, if you check Application - Cookies panel in Chrome (or corresponding panel in other browsers), you will find that: the cookie specified by Set-Cookie header is not there. Browser does not store it and won't send it in the following HTTP requests.
Also, please note that as the cookie's path is /base, only the HTTP requests whose URL starts with /base can send the cookie.

How to forward a request to other endpoint in node.js

In my scenario I need forward get request to another end point. In my machine there are two servers php and node.js server. Node.js is like a "man in the middle", PHP server must work in the same way.
Node.js server code
var express = require('express');
var fs = require('fs');
var path = require('path');
var http = require('http');
var https = require('https');
var app = express();
var HTTP_PORT = 3000;
// Create an HTTP service
http.createServer(app).listen(HTTP_PORT,function() {
console.log('Listening HTTP on port ' + HTTP_PORT);
});
//endpoint for tracking
app.get('/track', function(req, res) {
sendRequestToOtherEndPoint(req);
processRequest(req);
res.setHeader('Content-Type', 'application/json');
res.send('Req OK');
});
function processRequest(req){
console.log("request processed");
}
function sendRequestToOtherEndPoint(req){
//magic here :)
}
When this server receive a get request in port 3000, it process request information and it must forward the same requesto to another end point.
For example:
Get localhost:3000/track?param1=1&param2=2
Server process get request
Server forward get request to localhost/final-endpoint?param1=1&param2=2
Depending on what you're trying to do, you can create a new request to the end-point:
//endpoint for tracking
app.get('/track', function(req, res) {
req.get({url: 'http://end-point', headers: req.headers});
processRequest(req);
res.setHeader('Content-Type', 'application/json');
res.send('Req OK');
});
More info: https://github.com/request/request
There are a couple of useful libraries that one could use:
http-proxy-middleware:
const proxy = require('http-proxy-middleware')
var apiProxy = proxy('/track', {target: 'http://end-point'});
app.use(apiProxy)
axios-express-proxy
import express from 'express';
import { Proxy } from 'axios-express-proxy';
const app = express();
const port = 3000;
app.get('/track', (req, res) => Proxy('http://end-point', req, res));
In you case res.redirect might help.
app.get('/track', function(req, res) {
// process the request
// then redirect
res.redirect('/final-endpoint');
});
Then catch the redirected request in final endpont.
app.get('/final-endpoint', function(req, res) {
// proceess redirected request here.
});
See the Express docs
If your second endpoint is on a different server, (e.g. PHP) then you're going to need to either redirect the client (as in sohel's answer), or spoof a request from Node to the PHP server and then send the response back to the client. This latter option is definitely non-trivial so I would question whether it's crucial not to use a client redirect.
If you're talking about two express endpoints, then I think the simplest answer might be not to actually forward at all, but just use the endpoint callback directly instead:
app.get('/track', trackCallback);
app.get('/otherendpoint', otherendpointCallback);
function otherendpointCallback(req, res) {
// do your thing
}
function trackCallback(req, res) {
otherendpointCallback(req, res);
processRequest(req);
res.setHeader('Content-Type', 'application/json');
res.send('Req OK');
};
Depending on exactly what you want to do at the other end point, you might need to spoof some of req's fields (e.g. req.url)

proxying requests from a secure application

im trying to proxy requests from a secure web application(https) in node (its an internal application) and im not quite sure how to do it...
the below is my code which works when i try it from an non secured app (http).
It just strips out a page name and uses it in another app. I read the docs but still not sure how to do it. Do i need to have the ssl info from my application for this to work?
var http = require('http');
var httpProxy = require('http-proxy');
var request = require('request');
var app = require('express.io')();
app.http().io();
//
// Create proxy server
//
var proxy = httpProxy.createProxyServer({target:'http://localhost:9000'}).listen(9085);
// Send the client html.
app.get('/', function(req, res) {
res.sendfile(__dirname + '/client1.html');
})
proxy.on('error', function (err, req, res) {
res.writeHead(500, {
'Content-Type': 'text/plain'
});
res.end('Something went wrong!');
});
app.all('/Domain/*', function(req, res) {
console.log(req.url);
if (req.url.indexOf("Page.do") > -1) {
// URL to Atlas
var otherAppURL = "http://myotherapp/pages/";
var temp = req.url.split("Page.do")[0].split("/");
var pageName = temp[temp.length - 1];;
app.io.broadcast('update', {
url: atlasURL + pageName + '.html'
});
};
// This doesnt work
//var url = "https://mysecureapp:9044" + req.url;
// This works
var url = "http://localhost:9080" + req.url;
req.pipe(request(url)).pipe(res);
})
app.listen(9000);
Yes, you do need an SSL Certificate for an HTTPS connection. According to the website https://www.globalsign.com/en/ssl-information-center/what-is-an-ssl-certificate/ :
The standard HTTP is changed to HTTPS, automatically telling the browser that the connection between the server and the browser must be secured using SSL.
This means that with an HTTPS connection, you need to have the server secured with SSL.
For connecting with HTTPS in Node, this website might help you:
http://gaboesquivel.com/blog/2014/nodejs-https-and-ssl-certificate-for-development/
Ok i might be mistaking but this line doesn't make sense ,
req.pipe(request(url)).pipe(res);
by the time the route handler hits, the req object is ready
so req.pipe has no meaning.
please check that url returns a valid response
request(url).pipe(res); should work
http / https is not an issue

Resources