I have a scenario where I have two React applications. Application-1
opens Application-2
using an iframe.
I can access Application-2 either directly or through the Application-1 iframe. However, when I use the Application-1 iframe, it must go through multiple server hops to reach Application-2, something like the following.
Application-1
—-> Express-Server-1(serving Application-1 & forwarding request for Application-2) —-> Express-Server-2(proxy/passthrough) ——> Express-Server-3(serving Application-2)—–> Application-2
while I can access Application-2
directly I can’t access using Application-1 using an Iframe.
so below is the app.js
file which serves the Application-2
and is running on server-3
.
const createError = require("http-errors");
const express = require("express");
const cors = require('cors')
const path = require("path");
const fs = require("fs");
const cookieParser = require("cookie-parser");
// Server-static middleware
const {
appLogger,
expressLogger,
expressErrorLogger,
} = require("./lib/logger");
const {corsOptionsDelegate} = require("./routes/corsDelegate");
const app = express();
app.disable("x-powered-by");
app.options('*', cors());
// serves static pages
app.use("/application-2/static", express.static(path.join(__dirname, "public")));
// view engine setup
app.set("views", path.join(__dirname, "views"));
app.set("view engine", "jade");
app.use(express.json());
app.use(express.urlencoded({extended: false}));
app.use(expressLogger);
app.use(expressErrorLogger);
app.use(cookieParser());
app.use(
express.static(path.join(__dirname, ".", "webapp")),
(req, res, next) => {
try {
decodeURIComponent(req.url);
return next();
} catch (err) {
return res.status(400).json({message: "Invalid request"});
}
}
);
const managementRouter = require("./routes/management");
app.use("/application-2/management", managementRouter);
// serves the application-2 app
app.use("/application-2", express.static(path.join(__dirname, ".", "webapp")));
// connect to the "src/routes" directory
const routersPath = path.join(__dirname, "routes/v1");
// read all files in the "/src/routers" directory
fs.readdirSync(routersPath).forEach((file) => {
if (file.endsWith(".js")) {
// dynamically import the router module
const routerModule = require((path.join(routersPath, file).replace(".js","")));
// register the router
app.use(routerModule);
}
});
app.get("/application-2/unauthorized", cors(corsOptionsDelegate), function (req, res, next) {
res.status(403);
res.sendFile(path.resolve(__dirname, ".", "views", "unauthorized.html"));
});
// catch 404 and forward to error handler
app.use(function (req, res, next) {
next(createError(404));
});
// error handling
app.use(function (err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get("env") === "development" ? err : {};
// render the error page
res.status(err.status || 500);
res.render("error", {title: "ABC Images | application Search"});
});
module.exports = app;
below is code at server-1
to fetch application-2, i.e when application-1 opens iframe it makes a call to server-1 at /application-search
.
app.use("/application-search", createProxyMiddleware({
target: "http://localhost:9012",
changeOrigin: true,
logLevel: 'debug',
pathRewrite: (path, req) => {
// Extract the query string from the original URL
const queryString = req.url.split('?')[1] || "11x";
// Rewrite the path to include the query string
return `/?${queryString}`;
},
onProxyReq: (proxyReq, req, res) => {
let cookieArray = [];
try {
// Split the cookies into an array and log them
const cookies = req.headers.cookie || "";
cookieArray = cookies.split(';').map(row => {
return row.trim();
});
} catch (error) {
console.error('Error processing cookies:', error);
}
//const tokenCookie = cookieArray.find(row => row.startsWith('ckns_pp_id=')) || "";
const tokenValue = tokenCookie.split('=')[1].trim();
// Add custom headers if needed
proxyReq.setHeader('Authorization', `Bearer ${tokenValue}`);
}
}));
below is code at server-2
which when get request from server-1 will hit the server-3 that is serving application-2
app.use("/", createProxyMiddleware({
target: "https://xxx.co.uk/application-2",
changeOrigin: true,
logLevel: 'debug',
pathRewrite: (path, req) => {
// Extract the query string from the original URL
const queryString = req.url.split('?')[1] || "11x";
// Rewrite the path to include the query string
return `/?${queryString}`;
},
onProxyReq: (proxyReq, req, res) => {
// Add the authorization header
const bearerToken = req.headers['authorization'] || "";
proxyReq.setHeader('Authorization', bearerToken);
},
onProxyRes: (proxyRes, req, res) => {
console.log(`⬅️ Response from Server-3: ${proxyRes.statusCode} for ${req.url}`);
}
}));
I am either getting 404 not find “Not Found, when from application-1 I try to open iframe to show application-2
404
NotFoundError: Not Found
at /Users/abc01/projects/application-2/server/app.js:104:10
Currently I am using createProxyMiddleware
strategy to pass on the request, please do advise if there is a better strategy for this requirements, as I have to hop though the servers as there are some authentication requirements and can’t access the application-2
directly.