1

Main problem

How can I create in express a new request to Google Cloud Functions containing the same IP address as the original client request?
Or, how can I proxy the client request through express to Google Cloud Functions by preserving the IP address, so Google Cloud Functions shows me the client IP instead of the IP address of the nodejs server.

The code

Express app

// app.js
const express = require('express');
const request = require('request');
const nocache = require('nocache');
const cors = require('cors');

const API_ENDPOINT = 'https://project-name.cloudfunctions.net/cloudfunction-name';
const app = express();
const port = 3000;

app.use(nocache());
app.use(cors());

app.get('/test', function (req, res) {
  req.pipe(
      request({
          qs:req.query,
          uri: API_ENDPOINT,
          json: true,
          gzip: true,
          ip: req.ip
      }, (error, response, body) => {
          console.log(body)
          console.log(req.ip)
      })
  ).pipe(res);
});

app.listen(port, function () {
  console.log('Example app listening on port ' + port +'!');
});

CloudFunctions


const cors = require('cors')
const localeCode = require('locale-code');

function location(req, res) {

    let languages = req.acceptsLanguages();
    let lang = '';

    if(languages.length > 0){
        lang = localeCode.getLanguageCode(languages[0]);
    }

    let data = {
        country: req.headers["x-appengine-country"].toLowerCase(),
        region: req.headers["x-appengine-region"].toLowerCase(),
        city: req.headers["x-appengine-city"].toLowerCase(),
        userIP: req.headers["x-appengine-user-ip"],
        language: lang
    };
    // Json response is gzipped by CloudFunctions
    res.json(data)
}


exports.init = (req, res) => {
  const corsHandler = cors({ origin: true })

  return corsHandler(req, res, function() {
    return location(req, res);
  });
};

CloudFunctions Request looks like this. (Json is passed in the request "body")

{
  country: "de",
  region: "he",
  city: "frankfurt",
  userIP: "35.xxx.xxx.xxx",
  language: "de",
}

What I've tried so far

I've searched for hours and couldn't find any example, how this can be achieved.

According to my understanding, this code portion should pipe (proxy) the client request to the CloudFunctions api and back to the requester (express app) by preserving the request.

  req.pipe(
      request({
          qs:req.query,
          uri: API_ENDPOINT,
          json: true,
          gzip: true,
          ip: req.ip
      }, (error, response, body) => {
          console.log(body)
          console.log(req.ip)
          // Here comes the logic for redirecting clients
      })
  ).pipe(res);

Also adding or removing this snippet below makes no difference. The userIP in the response object allways contains the server IP instead of the client IP.

ip: req.ip
  • Why do you want to perform the request on behalf of the userIP? Do you try [this](https://github.com/http-party/node-http-proxy) – guillaume blaquiere Oct 23 '19 at 11:03
  • in this [thread](https://stackoverflow.com/questions/16437950/http-change-request-url) they talk about modifying requests with nodejs. another option is [here](https://www.npmjs.com/package/node-tunnel) is an option using tunneling, which might work for you. – Soni Sol Oct 25 '19 at 19:12
  • My idea was to use the available X-Appengine-Country HTTP header in Google Cloud Functions to redirect users to a specific website based on their IP address. I would like to implement this functionality in a small express app. – Markus Liechti Oct 28 '19 at 06:50
  • I've tested it also with the node-http-proxy and I get the same result. – Markus Liechti Oct 28 '19 at 06:53
  • are you modifying the request at the intermediate point? in terms of content – Soni Sol Oct 30 '19 at 22:07
  • @MarkusLiechti Oh I need to achive same thing now... Did you find a soulation ? – Ghyath Darwish Feb 24 '21 at 12:50

0 Answers0