2

I have read a lot of answers but couldn't able to find anything satisfactory. The user roles in the application depend on the information I will receive in headers. I have already tried this:

var req = new XMLHttpRequest(); req.open('GET', document.location,false); req.send(null); 
var headers = req.getAllResponseHeaders().toLowerCase(); alert(headers);

But i think i generates a new request and by then the URL changes so the headers are not the same. If there is any other option to get the headers please guide me with the same

Edit 1 (This will clarify the question a little more):

  • The user would click on my application(Let's say application1) link via another application (Let's say application2).
  • Then the applicaion2 will send the HTTP/HTTPs headers in requests forwarded by the reverse proxy, which will contain user role and some more information.
  • In the headers I will receive user roles.
  • Depending on the role the kind of access would be determined and given to user
Sankalp Chawla
  • 39
  • 1
  • 2
  • 9
  • 1
    the request headers will obviously be sent by the browser to your server - so, your server can read these request headers ... and can send the info back in the response if you want (and you can write code on the server) – Bravo Oct 17 '19 at 05:39
  • Your question is not very clear. However, I suggest you to use https://github.com/axios/axios for large applications. – James Oct 17 '19 at 05:40
  • @Sankalp Chawla, Make sure you mark the answer which helped you to solve the issue as accepted. So, it will help the future visitors. – James Oct 17 '19 at 06:38

3 Answers3

0

As this question/answer clarifies, getting the original response headers for the page is not possible in javascript. But in any case, this is not the way to achieve robust user access control. Rather, you want the server to provide those details to the client, having read and parsed the original request headers.

see sharper
  • 11,505
  • 8
  • 46
  • 65
0

If I understand your question correctly, It seems you are trying to get the request headers on initial page load.

At present, there is no API to give you the HTTP response headers for your initial page request. However, you can get and set headers on AJAX requests.

1. Make an ajax request on page load.

So, the easier solution is to simply make an AJAX request to the server on page load. As you are using ReactJS, make the request on componentDidMount

componentDidMount() {
    var req = new XMLHttpRequest();
    req.open('GET', document.location, false);
    req.send(null);
    var headers = req.getAllResponseHeaders().toLowerCase();
    headers = headers.split(/\n|\r|\r\n/g).reduce(function(a, b) {
        if (b.length) {
            var [ key, value ] = b.split(': ');
            a[key] = value;
        }
        return a;
    }, {});
    console.log(headers);
}

Here is the working demo

2. Using web workers.

Another solution I can suggest is to take help of service workers. You can use https://github.com/gmetais/sw-get-headers and implement it in your application.

// Needed because the library uses browserify
var swgetheaders = require('swgetheaders');

// Register the service worker (with some options)
swgetheaders.registerServiceWorker('/swgetheaders-worker.js', {
    debug: true,
    corsExceptions: [
        'code.jquery.com',
        'platform.twitter.com'
    ]
});

swgetheaders.on('plugged', function() {
    console.log('The service worker is now activated and ready to listen to requests');
});

swgetheaders.on('response', function(request, response) {
    console.log('A response just arrived. We have both the request and the response:', request, response);
});
Community
  • 1
  • 1
James
  • 2,874
  • 4
  • 30
  • 55
  • I went through the documentation of web workers but I didn't quite get what is happening. Can you please explain a little how is it working? – Sankalp Chawla Oct 18 '19 at 03:36
  • Moreover, I found this in the documentation: **Please note that the worker will not be available on the first page load, but only after a page change or a reload. This is due to some limitations in Service Workers.** . So I guess it defeats the purpose as I explained in my question and I have already tried first option but no luck. – Sankalp Chawla Oct 18 '19 at 03:51
  • You can use it on initial page load. You just have to register the worker in your top level `React componet` before you do the authorisation, so that it will be ready with data to authorise the roles. I'm not sure for where you got the information that you mentioned in above comment. Webworkers will be available immediately once you register in your application. And it runs on a separate thread, so it uses `Broadcasting` mechanism to communicate with the main thread. – James Oct 18 '19 at 05:48
  • Here is the documentation which explains it clearly https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers – James Oct 18 '19 at 05:49
  • Also you can refer to the service worker which react creates when you create an app using `create-react-app` https://github.com/vish25v/react-todo-list/blob/master/src/registerServiceWorker.js And this question have some example https://stackoverflow.com/questions/47475360/creating-a-web-worker-inside-react – James Oct 18 '19 at 06:01
  • I tried this approach: `var swgetheaders = require('./swgetheaders-page'); // Register the service worker (with some options) swgetheaders.registerServiceWorker('./swgetheaders-worker', { debug: true, corsExceptions: [ 'code.jquery.com', 'platform.twitter.com' ] });` But I am getting error: **TypeError: swgetheaders.registerServiceWorker is not a function** I added both the files in the project. – Sankalp Chawla Oct 18 '19 at 07:39
  • The error is due to the build tool you are using in React. The script is designed to work in normall web pages. You can check my demo https://codesandbox.io/s/so-page-header-service-worker-1tlgk This demo doesn't register the worker due to the limitation of sandbox. But, you can try the same locally. – James Oct 18 '19 at 09:05
  • I tried to do the same locally and with some tweaks as well, But it doesn't work. Still stuck with same error. – Sankalp Chawla Oct 18 '19 at 10:29
  • Tried from sandox...still stuck with same issue – Sankalp Chawla Oct 22 '19 at 04:24
  • It should be either import issue or script. However, I cannot guess what is cause of error in your case. Maybe you can create a sandbox to reproduce the issue. Or you can try with the first approach in my answer. – James Oct 22 '19 at 05:31
0

After converting the application to server-side rendering I was able to get the headers with the following script:

import path from 'path'
import fs from 'fs'
import express from 'express'
import React from 'react'
import ReactDOMServer from 'react-dom/server'
import { StaticRouter } from 'react-router-dom';
import App from '../src/App'
import UserContext from '../src/config/UserContext'
import serialize from "serialize-javascript"
const https = process.env.NODE_ENV === "production" ? require("spdy") : require("https")
var privateKey = fs.readFileSync(path.resolve(__dirname, "file.key"), 'utf8');
var certificate = fs.readFileSync(path.resolve(__dirname, "file.cer"), 'utf8');
var credentials = { key: privateKey, cert: certificate };

const tls = require('tls');
tls.DEFAULT_MIN_VERSION = 'TLSv1';

const PORT = anyport
const app = express()
var httpsServer = https.createServer(credentials, app);
const router = express.Router()



const serverRenderer = (req, res) => {
  const context = {};
  //console.log(req.headers);
  var a = 'anything';
  var b = 'anything';
  //console.log(req.headers["variable_name_in_header"]);
  var reqHeaders = req.headers;
  console.log(reqHeaders);
  if ("variable_name_in_header" in reqHeaders) {
   
    //anything

  }
  
  
  const initialState = { a, b };
  //const appString = ReactDOMServer.renderToString(<StaticRouter location={req.url} context={context}><App {...initialState} /></StaticRouter>);

  const appString = ReactDOMServer.renderToString(

    <StaticRouter location={req.url} context={context} basename={'/'}>
      <App {...initialState} />
    </StaticRouter>

  );

  fs.readFile(path.resolve('./build/index.html'), 'utf8', (err, data) => {
    if (err) {
      console.error(err)
      return res.status(500).send('An error occurred')
    }

    return res.send(
      data.replace(
        '</body>',
        `<script>window.__INITIAL_DATA__ = ${serialize(initialState)}</script></body>`
      ).replace(
        '<div id="root"></div>',
        `<div id="root">${appString}</div>`
      )
    )
  })

}

router.use('^/$', serverRenderer)

router.use(
  express.static(path.resolve(__dirname, '..', 'build'), { maxAge: '30d' })
)

// tell the app to use the above rules
app.use(router)

// app.use(express.static('./build'))
httpsServer.listen(PORT, () => {
  console.log(`SSR running on port ${PORT}`);
})
Sankalp Chawla
  • 39
  • 1
  • 2
  • 9