Angular image not served properly from nodejs backend - node.js

I want to serve a image from my nodejs backend and show it in frontend, my backend running at 8081 port and frontend at 8080. I can see images in http://localhost:8081/image.JPG but in frontend I am getting 404 as it is looking for http://localhost:8081/image.JPG.
var express = require('express');
var cors = require("cors");
var bodyParser = require('body-parser');
var app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
global.__basedir = __dirname;
app.use(express.static(__dirname + '/resources/static/assets/uploads/'));
app.use(function (req, res, next) {
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:8080');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
// Request headers you wish to allow
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');
// Set to true if you need the website to include cookies in the requests sent
// to the API (e.g. in case you use sessions)
res.setHeader('Access-Control-Allow-Credentials', true);
// Pass to next layer of middleware
next();
});
const db = require('./app/config/db.config');
app.use(cors({origin: 'http://localhost:8080'}));
// force: true will drop the table if it already exists
db.sequelize.sync({force: false}).then(() => {
console.log('Drop and Resync with { force: false }');
});
require('./app/routers/upload.router.js')(app);
// Create a Server
var server = app.listen(8081, function () {
var host = server.address().address
var port = server.address().port
console.log("App listening at http://%s:%s", host, port)
})
i can see image when i query in browser as it is looking for 8081 port
frontend looking for port 8080 so getting below error--
someone please suggest me a solution. I am not getting any clue. Thank you.

An approach that you can take is to use proxy config provided by Angular like below:
{
"/api/assets": {
"target": "http://localhost:8081",
"secure": false
}
}
Now, from the frontend when you hit this URL: http://localhost:8080/api/assets/image.JPG it will proxy to http://localhost:8081/api/assets/image.JPG
your image tag will look like <img src="/api/assets/image.JPG">
More on Proxy config & how to configure: https://angular.io/guide/build#proxying-to-a-backend-server

Related

getting CORS error when I try to fetch my api

When I try to fetch my API from my react app, it shows me this error message when my laptop is connected through a LAN connection.
But when my laptop is connected through a mobile hotspot, it doesn't show me any error.
And when I run my API in localhost:5000, it shows me this error message on the terminal.
Could not connect to any servers in your MongoDB Atlas cluster. One common reason is that you're trying to access the database from an IP that isn't whitelisted. Make sure your current IP address is on your Atlas cluster's IP whitelist: https://docs.atlas.mongodb.com/security-whitelist/
I already give access to my IP address and it's working fine when I connected through a mobile hotspot.
Why is it happening and how to fix this?
I am able to fetch other APIs but not mine.
API link: https://invoicesapi.herokuapp.com/api/invoices
Github Repo: https://github.com/rishipurwar1/invoice_api
API app.js code:
const path = require('path');
const express = require('express');
const app = express();
const port = process.env.PORT || 5000;
const connectDB = require('./config/db');
// routes
const invoices = require('./routes/api/invoices');
// Init Middleware
app.use(express.json({ extended: false }));
app.use((req, res, next) => {
res.setHeader('Access-Control-Allow-Origin', "*");
res.setHeader('Access-Control-Allow-Methods', "POST,GET,OPTIONS");
res.setHeader('Access-Control-Allow-Headers', "Content-Type, Authorization");
if (req.method === 'OPTIONS') {
return res.sendStatus(200);
}
next();
});
app.set('views', path.join(__dirname, 'views'))
app.set('view engine', 'ejs')
// Connect Database
connectDB();
app.get('/api', (req, res) => {
res.render('index')
});
app.use('/api', invoices);
app.listen(port, () => {
console.log('Server is started');
})
You should consider using the cors package (https://www.npmjs.com/package/cors)
npm install cors
Add this to app.js file:
var cors = require('cors')
var corsOptions = {
origin: 'http://yoursite.com',
optionsSuccessStatus: 200
}
app.use(cors(corsOptions))

How to integrate OKTA SAML with NodeJS or AngularJS

I have a Web Application using NodeJS + AngularJS, I want to integrate OKTA SAML with my application(Using Okta as IdP, using our Application as SP), right now I have some info after configuration on Okta End, it like this:
https://www.pastepic.xyz/image/image.abqL4
https://www.pastepic.xyz/image/image.ab3G3
I have Idp Single-Sign On URL, IdP Issuer, X.509 Certificate and also MetaData.
My question is how to integrate it with NodeJS oR AngularJS, How should I use the data from okta.
I have tried to use passport library in NodeJS, the app.js like this:
var express = require("express");
var path = require("path");
var bodyParser = require("body-parser");
var routes = require("./api/routes");
var http = require("http");
var morgan = require('morgan');
var cookieParser = require('cookie-parser');
var session = require('express-session');
var passport = require('passport');
require("./api/helper/global_function");
// Defining the port and env to run on
const { environment, port, samlUrl } = require('./appconfig.js');
const PORT = port || 8000;
const ENV = environment || 'dev'
const SAMLURL = samlUrl
const config = require('./api/auth/config.js')[ENV];
require('./api/auth/passport.js')(passport, config);
var app = express();
app.set("port", PORT);
app.set("env", ENV)
app.set("samlUrl", SAMLURL)
// To Allow CORS calls
app.use(function (req, res, next) {
res.header('Access-Control-Allow-Origin', '*')
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
res.header('Access-Control-Allow-Credentials', true);
return next();
});
app.use(morgan('combined'));
app.use(cookieParser());
app.use(session(
{
resave: true,
saveUninitialized: true,
secret: 'something'
}));
// Enable parsing of posted forms
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(passport.initialize());
app.use(passport.session());
// Set static directory before defining routes
app.use(express.static(path.join(__dirname, "dist")));
app.use("/node_modules", express.static(__dirname + "/node_modules"));
// Add some routing
app.use("/", function (req, res, next) {
if (req.isAuthenticated()) {
console.log(req.isAuthenticated())
return next();
}
req.session.returnTo = req.originalUrl;
res.redirect(samlUrl);
});
app.use("/api", routes);
app.use("*", (req, res) => {
res.sendFile(path.join(__dirname, 'dist/index.html'));
});
// To verify the listen is up and running
var server = app.listen(app.get("port"), function () {
var port = server.address().port;
console.log("Magic happens on port " + port);
});
It doesn't work because all request is unauthenticated, when I make a api call, the application keep directing me to single sign on page.
Maybe I am absolutely wrong about this, can somebody help me out? Give me a hint or tell me some basic logic
Can any people help with SAML? If any unclear, please add a comment or answer, I will check in a very short time.

React axios calls to Express API in Heroku deployment

I have a React todo app I built using create-react-app and I built a simple express server to query mongoDB to get all the appointment objects. It works just as expected when I am running it on my machine. The front end spins up on localhost:3000 and the server on localhost:3001. I use axios to make a get request to localhost:3000/api/appointments to load all the appointments into the App.js state. I uploaded it to Heroku and I got a CORS error on the request. After that, I tried to just use the route 'api/appointments' in the request and every permutation of that I can come up with which all respond with 404 errors.
Where does the node.env variable spin up the server on Heroku? And how do I call it fromm a React app with axios?
Same question in a different context if it helps:
When I run the app on my machine and access it with Postman, I can GET localhost:3001/api/appointmentsand it returns an array of JSON objects from the database just as I would expect. When I deploy to Heroku GET https://appointment-ledger-map.herokuapp.com/api/appointments returns all the markup for index.html. I assume this means that the api server is up and running because it responds but why is it not responding with the array of JSON objects as expected?
// server.js
var express = require('express');
var mongoose = require('mongoose');
var bodyParser = require('body-parser');
var Appointment = require('./model/appointments');
//and create our instances
var app = express();
var router = express.Router();
//set our port to either a predetermined port number if you have set
//it up, or 3001
var nodeEnv = process.env.NODE_ENV || 'development';
var port = process.env.PORT || 3001;
var host = process.env.HOST || '0.0.0.0';
//db config
mongoose.connect('mongodb://josh11:josh11#ds133162.mlab.com:33162/heroku_tl016m5d');
//now we should configure the API to use bodyParser and look for
//JSON data in the request body
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
//To prevent errors from Cross Origin Resource Sharing, we will set
//our headers to allow CORS with middleware like so:
app.use(function(req, res, next) {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Credentials', 'true');
res.setHeader('Access-Control-Allow-Methods', 'GET,HEAD,OPTIONS,POST,PUT,DELETE');
res.setHeader('Access-Control-Allow-Headers', 'Access-Control-Allow-Headers, Origin,Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers');
//and remove cacheing so we get the most recent appointments
res.setHeader('Cache-Control', 'no-cache');
next();
});
//now we can set the route path & initialize the API
router.get('/', function(req, res) {
res.send({ message: 'API Initialized!'});
console.log('Api initialized');
});
//Use our router configuration when we call /api
app.use('/api', router);
//starts the server and listens for requests
app.listen(port, host, function() {
console.log(`api running on port ${port}`);
});
//adding the /appointments route to our /api router
router.route('/api/appointments')
//retrieve all appointments from the database
.get(function(req, res) {
//looks at our Appointment Schema
Appointment.find(function(err, appointments) {
if (err)
res.send(err);
//responds with a json object of our database appointments.
res.send(appointments)
});
console.log(appointments);
})
//post new appointment to the database
.post(function(req, res) {
var appointment = new Appointment();
//body parser lets us use the req.body
appointment.appointmentTitle = req.body.appointmentTitle;
appointment.appointmentDate = req.body.appointmentDate;
appointment.appointmentTime = req.body.appointmentTime;
appointment.appointmentDescription = req.body.appointmentDescription;
appointment.appointmentDestination = req.body.appointmentDestination;
appointment.appointmentOrigin = req.body.appointmentOrigin;
appointment.travelMode = req.body.travelMode;
appointment.save(function(err) {
if (err)
res.send(err);
res.send({ message: 'Appointment successfully added!' });
});
});
// App.js
loadAppointments() {
axios.get('/api/appointments')
.then(res => {
this.setState({
appointments: res.data,
filteredAppointments: res.data
});
})
}
npm install cors --save
then
var cors = require('cors');
finally
mongoose.connect('mongodb://josh11:josh11#ds133162.mlab.com:33162/heroku_tl016m5d');
//now we should configure the API to use bodyParser and look for
//JSON data in the request body
app.use(cors()); **//Must be before BodyParser**
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
//To prevent errors from Cross Origin Resource Sharing, we will set
//our headers to allow CORS with middleware like so:
Re-deploy it and voila :)
Hope it helped you

Accessing internal API with React, Axios on Heroku

I am building a full stack React application that accesses its own back end API with Axios. In my local environment, the following works as expected, with the server responding with JSON data, which is then rendered properly.
axios.get('/api/questions/categories')
I deployed to Heroku, and the app is launching normally and MongoDB is connected. Now, when the same GET request is made, it is not reaching the back end. When I log the response from Axios to the console, it contains the actual HTML of the page, instead of the JSON object expected.
For further clarification, if I manually type 'http://localhost:8080/api/questions/categories' in the address bar, the expected JSON data is displayed. If I do the same with the app on Heroku, I see that a '#' is appended to the url and the page display does not change, no error messages. This leads me to think that react-router is involved, but I have not been able to figure out how/why.
My stack: Node, Express, Mongo, React
Not using Redux
Using Axios to call my own API
// Dependencies
var express = require('express');
var path = require('path');
var webpack = require('webpack');
var webpackMiddleware = require('webpack-dev-middleware');
var webpackHotMiddleware = require('webpack-hot-middleware');
var config = require('./webpack.config.js');
var bodyParser = require('body-parser');
var mongoose = require('mongoose');
var morgan = require('morgan');
var inDev = process.env.NODE_ENV !== 'production';
var port = inDev ? 8080 : process.env.PORT;
var app = express();
// MIDDLEWARE
if (inDev){
var compiler = webpack(config);
var middleware = webpackMiddleware(compiler, {
publicPath: config.output.publicPath,
contentBase: 'app',
stats: {
colors: true,
hash: false,
timings: true,
chunks: false,
chunkModules: false,
modules: false
}
});
app.use(morgan('dev'));
app.use(middleware);
app.use(webpackHotMiddleware(compiler));
app.get('/', function response(req, res) {
res.write(middleware.fileSystem.readFileSync(path.join(__dirname, 'dist/index.html')));
res.end();
});
} else {
app.use(express.static(__dirname + '/dist'));
app.get('*', function response(req, res) {
res.sendFile(path.join(__dirname, 'dist/index.html'));
});
}
app.use(bodyParser.urlencoded({extended: true}));
app.use(bodyParser.json());
app.use(function(req, res, next) {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Credentials', 'true');
res.setHeader('Access-Control-Allow-Methods', 'GET,HEAD,OPTIONS,POST,PUT,DELETE');
res.setHeader('Access-Control-Allow-Headers', 'Access-Control-Allow-Headers, Origin,Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers');
//and remove caching so we get the most recent comments
res.setHeader('Cache-Control', 'no-cache');
next();
});
// DATABASE
var dbPath = inDev ? 'mongodb://localhost/quizMe' : 'mongodb://heroku_pmjl5579:c28cf07fpf05uus13ipjeur5s7#ds143000.mlab.com:43000/heroku_pmjl5579';
mongoose.connect(dbPath);
// ROUTING / API
// var indexRoute = require('./routes/index');
var questionsRoute = require('./routes/api/questions');
// app.use('/', indexRoute);
app.use('/api/questions', questionsRoute);
app.listen(port, function(){
console.log('Express server up on ' + port);
});
Thanks for any help!
Most single page applications route all requests to the root path and let the front end router take over. I suspect that is what is happening to your app.
Do you have any form of requests redirection logic in your back end code or any server configuration code?
What you can do is to whitelist some paths that you don't want front end routing to take over, such as those that start with /api. Pasting your server side config here will be helpful.
In your server config, when inDev is false, you have a app.get('*', ...) that catches all requests and responds with the static single page app. Hence API requests will also give the same response. You will need to restructure your routes to match /api before the wildcard *. Some examples can be found here

Cross-Domain requests with ShareJS

I am trying to develop a plugin for DokuWiki that will enable real-time collaborative editing of wiki pages. I am using Node.js and ShareJS to do so, but I am having some trouble since it's the first time I am using them...
What I got so far is based on this and this pages.
ShareJS Server - http://localhost:3000
var express = require('express');
var app = express();
app.use(function(req, res, next) {
res.header('Access-Control-Allow-Origin', 'http://localhost:3000');
res.header('Access-Control-Allow-Methods', 'GET, OPTIONS');
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
res.header('Access-Control-Allow-Credentials', true);
return next();
});
// public folder to store assets
app.use(express.static(__dirname + '/public'));
// get sharejs dependencies
var sharejs = require('share');
require('redis');
// options for sharejs
var options = {
db: {type: 'redis'},
browserChannel: { cors: "http://localhost/dokuwiki/" },
};
// attach the express server to sharejs
sharejs.server.attach(app, options);
// listen on port 3000 (for localhost) or the port defined for heroku
var port = process.env.PORT || 3000;
app.listen(port);
Which by the way outputs this warning when I run it:
DokuWiki
When editing a wiki page, say http://localhost/dokuwiki/doku.php?id=start&do=edit, the plugin includes these scripts:
http://localhost:3000/channel/bcsocket.js
http://localhost:3000/share/share.js
http://localhost:3000/share/textarea.js
And then executes this:
window.onload = function() {
// get dokuwiki editor textarea element
var pad = document.getElementById('wiki__text');
if (pad) { // if a wiki page is being edited
// Server options
var options = {
origin: "http://localhost:3000/channel"
};
// Connect to the server
var connection = sharejs.open('test', 'text', options, function(error, doc) {
doc.attach_textarea(pad);
});
}
};
Which lead to the following errors on the DokuWiki page editor:
What am I missing? Thanks in advance!
Managed to solve it! :) The DeprecationWarning is still there and I don't know why, but it's working now.
All it took was editing the ShareJS Server code:
Removed the browserChannel: { cors: "http://localhost/dokuwiki/" }, line from the ShareJS options
Tweaked with the Access-Control-Allow-Origin middleware
Here's the "final" ShareJS Server code:
var express = require('express');
var app = express();
var port = 3000;
app.use(function (req, res, next) {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With, content-type');
res.setHeader('Access-Control-Allow-Credentials', true);
next();
});
// public folder to store assets
app.use(express.static(__dirname + '/public'));
// get sharejs dependencies
var sharejs = require('share');
require('redis');
// options for sharejs
var options = {
db: {type: 'redis'},
};
// attach the express server to sharejs
sharejs.server.attach(app, options);
app.listen(port, function() {
console.log('listening on *:' + port);
});
And that's it! Now I just need to edit this code a bit more to make different wiki pages have different ShareJS textareas.

Resources