NodeJS Request handler - node.js

I have some issues with a server that does not support IPv6 requests from Apple Application Review. So they reject my update.
And i'm thinking of making a request handler as a middle server, with nodejs.
So my app will send the requests in my new server, which server will send the request to the old server, take the response json back, and serve it back as well in my app.
So lets say the old webserver request was the following
https://www.example.com/example/api/index.php?action=categories&subaction=getproducts&category_id=100304&limit=0,30
But the request parameters are not always the same!
It may vary but the main URL is always the same
https://www.example.com/example/api/index.php?
The question is how to get the request params dynamically, make a request to the old webserver and return the response to the request of the new webserver?

You just need a very simple proxy like this;
const express = require('express')
const request = require('request')
const app = express()
const BASE_URL = 'http://www.google.com' // change accordingly
app.use('/', (req, res) => {
request({
url: BASE_URL + req.originalUrl
}).pipe(res)
})
app.listen(8900, () => console.log('Listening...'))
req.originalUrl will allow to concatenate the path + the query string to your base url

Related

Express.js Find URL of client consuming REST API

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');
// ...
});

NextJS - Sending cookies to API server from getInitialProps

I'm using NextJS as a client side repository to talk to my backend API server (laravel). Auth is done via JWT stored in the cookies. It all works seamlessly when I send an auth request to https://my-backend-server.com/api/login, as I respond with a cookie, and set to the my-backend-server.com domain. And even when I send requests from the browser.
Problems arise when I want to load the page, and sent the request from getInitialProps, as this is a serverside call. How am I able to access the cookies to my-backend-server.com, and put those in the header, so the server-side request from NextJS is properly authorized?
Most of the answers say something about req.cookies or req.headers.cookies, however this is empty as the request in getInitialProps is to http://my-local-clientside-site.com
As you explained correctly, Next's getInitialProps is called on client & on server.
If your Next app & Api services are served from the same domain, your Api service can put the cookie on the domain, and it will work on the client side (browser).
Whenever your Next app accessing the api from server-side, you need to attach the cookie by yourself.
getInitialProps method on the server side gets on the context (first param) the request (as req) from the browser, that means that this request has the cookie.
If you have a custom server, you probably need add to it a cookieParser,
// server.js
import cookieParser from 'cookie-parser';
import express from 'express';
import next from 'next';
const dev = process.env.NODE_ENV !== 'production';
const app = next({ dev });
app.prepare().then(() => {
const nextHandler = app.getRequestHandler();
const server = express();
server.use(cookieParser());
// -----------^
server.get('*', (req, res) => nextHandler(req, res));
});
This parser will parse the Cookie header and put it as an object on the req.
After that, your req.cookie should have the cookie value (make sure that you see that the browser sends it in the document request) you can access it in your getInitialProps,
//pages/index.js
const IndexPage = () => <div>BLA</div>
IndexPage.getInitialProps = (context) => {
if(context.req) {
// it runs on server side
axios.defaults.headers.get.Cookie = context.req.headers.cookie;
}
};
I've given you an example that sets up axios to put the cookie on all requests that will be made from the client.
Felixmosh' answer is half correct. rather than context.req.cookie it should be context.req.headers.cookie.
const IndexPage = () => <div>BLA</div>
IndexPage.getInitialProps = (context) => {
if(context.req) {
// it runs on server side
axios.defaults.headers.get.Cookie = context.req.headers.cookie;
//make api call with axios - it would have correct cookies to authenticate your api call
}
};

Why and how this simple node.js proxy works?

I have a frontend-only web application on Netlify which has to consume an API on OpenSubtitles.org. Although OpenSubtitles.org enables CORS, sometimes I got preflight errors, so I decided to use a proxy.
I had problems using Netlify's proxy feature, so I decided I will create my own proxy on Heroku, and send my requests from the frontend to there, so these will be proxied to OpenSubtitles.org from a server.
I came up with the following based on the code I found here:
const express = require('express');
const request = require('request');
express()
.use('/', function(req, res) {
req.pipe(
request({
url: 'http://rest.opensubtitles.org/search' + req.url,
headers: {
'User-Agent': 'TemporaryUserAgent'
}
})
).pipe(res);
})
.listen(process.env.PORT || 8000);
I thought I deploy this, try it out, then I will enable CORS on it after that. However I've just realized it is working perfectly without doing anything else. How is it possible? Why can I call this from a frontend-only app on a different domain without explicitly enabling CORS?
Also, what if the server crashes, how to handle the errors there?
CORS is working because the url you're requesting responds with the header Access-Control-Allow-Origin set with a value of *. Since you're piping that response and its headers back to the original res object, it will enable CORS as if it was coming from your local proxy.
Below is a more straightforward example of how to proxy a request to another site and return its response intact using node streams.
const express = require('express')
const request = require('request')
const port = process.env.PORT || 1337
let server = express()
const proxyMiddleware = (req, res, next) => {
let url = `https://www.google.com/${req.url}`
let proxyRequest = request(url)
// Pass request to proxied request url
req.pipe(proxyRequest)
// Respond to the original request with the response from proxyRequest
proxyRequest.pipe(res)
}
server.use(proxyMiddleware)
server.listen(port, () => console.log(`Listening on ${port}`))

Forward request object(POST) from express js server to another express js server

I want to forward a post request from an express server(from inside post method) to another express server's post method.
Is there any way to do that?
var httpProxy = require('http-proxy');
var apiProxy = httpProxy.createProxyServer();
var lb = 'http://localhost:8000';
after that inside post,
app.post('/emaillist', function(req, res){
console.log(req.body); // printing params correctly
console.log('redirecting to loadbalancer');
console.log(req.body);
apiProxy.web(req, res, {target: lb});
Here problem is that I can't retrieve request paramaters/body sent, in loadBalancer server. When trying to retrieve a property(e.g. email) out of request loadBalancer,
console.log(req.body.sender);
It says cant read a property of undefined.
My question is how to send request to another noder server from a node server and how to retrieve request parameters out of it at receiving node server

Cross-domain POST request in Node.JS with preflight?

I have just started with Node.
I am trying to get cross-domain form data from an HTML form to parse in a Node.js server. I have been able to do this with simple POST data, not with POST requests that require preflight.
I am running the Node code on cloud9 app servers. I am also using the Cors module to handle the requests. This module works well with simple requests (test here to see a simple request work), however with requests that require preflight I get this result from the Chrome inspector console.
XMLHttpRequest cannot load https://nms-motaheri-1.c9.io:8080/mail.
The request was redirected to 'https://c9.io:8080/api/nc/auth?.....SHORTENED',
which is disallowed for cross-origin requests that require preflight.
Here is my server.js code:
// Define dependencies
var express = require('express')
, cors = require('cors')
, app = express()
, parse_post = require("parse-post");
// Core module config
var corsOptions = {
origin: '*',
preflightContinue: true // <- I am assuming this is correct
};
app.use(cors(corsOptions));
// Respond to option request with HTTP 200
// ?? Why is this not answering my OPTION requests sufficiently ??
app.options('*',function(req,res){
res.send(200);
});
// Give a hello world response to all GET requests
app.get('/',function(req,res){
res.sendFile(__dirname + '/index.html');
});
// Handle all POST requests to /mail
app.post('/mail', parse_post(function(req, res) {
console.log(req.body);
res.json({msg: 'This is CORS-enabled for all origins!'});
})
);
// Listen on default Cloud9 port which is 8080 in this case
app.listen(process.env.PORT, function(){
console.log('CORS-enabled web server listening on port ' + process.env.PORT);
});
Why is this happening and how can I satisfactorily answer the OPTION request for my POST with pre-flight?
Here is the post request and response in Chrome dev tools:
Turns out that part of the problem was that the cloud9 server was set to private making these requests all redirect.
After making the server public, the redirections stopped. However, I received an error that the Node.js server did not have any Access-Control-Allow-Origin headers to allow requests from my cross origin domain. I noticed that "simple" with-out preflight requests would go through. So instead of trying to understand why it was not accepting my allow-all-origin-configuration on the Node.js side I decided to serialized the POST data to get rid of the preflight requirement and changed the data type in my angular request to plain text.
To get rid of preflight, first get rid of any POST header configuration (cache, etc), make sure your request Content-Type is plain text and make sure your actual content is plain text too. So if it is in JSON serialize it in jQuery before sending it with POST.
This is what my new Angular Post request code looked like:
sendEmail: function(email) {
var config = {
headers: {
'Content-Type': 'text/plain'
}
};
var POSTDATA= JSON.stringify(POSTDATAJSON);
return $http.post(POSTURL, POSTDATA, config)
}
And in Node.js this, I am using the cors Node.js module:
app.post('/mail', parse_post(function(req, res) {
var postReq = JSON.parse(Object.keys(req.body));
}));

Resources