I'm using http-proxy-middleware to setup request proxy from auth service to secured API.
Here I need to add custom header with authenticated user auth ID for every incoming request to the authentication layer. But with following implementation header not adding to the request. Here I've used on.proxyReq,
app.use('/info', auth, createProxyMiddleware({
target: process.env.BASE_API_URL,
changeOrigin: false,
on: {
proxyReq: (proxyReq, req, res) => {
console.log(`On Proxy Request ${proxyReq}`);
proxyReq.setHeader('x-auth-user', 'b05ff410-fbba-11ec-bfce-ddefb9f79237');
},
proxyRes: (proxyRes, req, res) => {
console.log(`On Proxy Response ${proxyRes}`);
},
error: (err, req, res) => {
console.log(`On Error Request ${err}`);
},
},
}));
This issue has resolved with following,
app.use('/info', auth, createProxyMiddleware({
target: process.env.BASE_API_URL,
changeOrigin: false,
onError: (err, req, res, target) => {
res.writeHead(500, {
'Content-Type': 'application/json',
});
res.end({ message: 'Something went wrong on proxy request. Please retry.' });
},
onProxyReq: (proxyReq, req, res) => {
proxyReq.setHeader('x_auth_user', req.user.email);
}
}));
Related
I'm using http-proxy-middleware in my recat app as follows
module.exports = function (app) {
app.use(
"/api",
createProxyMiddleware(filter, {
target: "https://example.com/",
secure: false,
changeOrigin: false,
logLevel: "debug",
followRedirects: true,
onProxyReq: (proxyReq, req, res) => {},
onProxyRes: (proxyRes, req, res) => {
const exchange = `[${req.method}] [${proxyRes.statusCode}] ${req.path} ->
${proxyRes.req.protocol}//${proxyRes.req.host}${proxyRes.req.path}`;
console.log(exchange);
},
onError: (err, req, res, target) => {
console.log(err);
},
})
);
};
I set followRedirects = true otherwise I get a 301 and then a 405 Method not allowed
now I get just the 405 I can see that the request is changed to a 'GET' request which is rejected by the server
this is my request
axios({
method: "POST",
data: data,
url: url,
}).then(r =>{
...
})
I'm a trying to make a route accessible only if you are authenticated with JWT using below middleware but I can't seem to find a way to pass the token in the get request from client side ?
It works fine on postman and I if using a fetch from client side it won't redirect me to the page I want to go
auth.js
async function (req, res, next) {
const token = req.header('x-auth-token');
if (!token) {
return res.status(401).json({ msg: 'Forbidden' });
}
try {
const decoded = jwt.verify(token, process.env.TOKEN_SECRET);
req.user = decoded.user;
next();
} catch (e) {
return res.status(401).json({ err: 'fail' });
}
};
server side
router.get('/', auth, function (req, res, next) {
res.render('pages/person');
});
You can simply attach your token to the headers in the request and sent it with get or even 'delete` method.
for example, in the fetch method you can attach your token in this way in your client side:
fetch('URL_GOES_HERE', {
method: 'post',
headers: new Headers({
'Authorization': YOUR_TOKEN,
'Content-Type': 'application/x-www-form-urlencoded'
}),
});
Now, you can retrieve the token in the node app:
const token = req.headers.authorization || "";
I'm trying to make a post request with node.js and when I try to run it, I get the data to show up in the console but noot the body of my HTML. In the console I get the error
app.js:4 POST http://localhost:8000/addAnimal net::ERR_EMPTY_RESPONSE
postData # app.js:4
(anonymous) # app.js:25
app.js:21 Uncaught (in promise) TypeError: Failed to fetch
It seems like the function is working but not the actual post request part. I can't for the life of me figure out what I'm doing wrong.
This is my code:
server.js:
projectData = {};
/* Express to run server and routes */
const express = require('express');
/* Start up an instance of app */
const app = express();
/* Dependencies */
const bodyParser = require('body-parser')
/* Middleware*/
app.use(express.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
const cors = require('cors');
app.use(cors());
/* Initialize the main project folder*/
app.use(express.static('project1'));
const port = 8000;
/* Spin up the server*/
const server = app.listen(port, listening);
function listening(){
// console.log(server);
console.log(`running on localhost: ${port}`);
};
// GET route
app.get('/all', sendData);
function sendData (request, response) {
response.send(projectData);
};
// POST route
app.post('/add', callBack);
function callBack(req,res){
res.send('POST received');
}
// POST an animal
const data = [];
// TODO-Call Function
app.route('/addAnimal')
.get(function (req, res) {
res.sendFile('index.html', {root: 'project1'})
})
.post(function (req, res) {
data.push(req.body)
})
app.js
/* Function to POST data */
const postData = async ( url = '', data = {})=>{
console.log(data);
const response = await fetch(url, {
method: 'POST', // *GET, POST, PUT, DELETE, etc.
credentials: 'same-origin', // include, *same-origin, omit
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data), // body data type must match "Content-Type" header
});
try {
const newData = await response.json()
// console.log(newData);
return newData.json()
}catch(error) {
console.log("error", error)
// appropriately handle the error
};
};
// TODO-Call Function
postData('/addAnimal', {animal:'lion'});
Any help would be greatly appreciated.
Thanks,
Mike
💡 The only one reason why you got message like it, it's because you never send response to the client.
👨🏫 So, You should to send response to the client. For an example, you can look at this code below: 👇
app.route('/addAnimal')
.get(function (req, res) {
res.sendFile('index.html', {root: 'project1'})
})
.post(function (req, res) {
data.push(req.body);
// send data to client
// you can change req.body with the object what you want to sent do the client
res.status(200).send(req.body);
})
📤 Update: Addtional information
Make sure you call the endpoint: http://localhost:8000/addAnimal.
Frontend: Make sure your code like this code below
const postData = async ( url = '', data = {})=>{
const response = await fetch(url, {
method: 'POST', // *GET, POST, PUT, DELETE, etc.
credentials: 'same-origin', // include, *same-origin, omit
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data), // body data type must match "Content-Type" header
});
try {
console.log(await response.json());
return await response.json()
}catch(error) {
console.log("error", error);
};
};
I hope it can help you 🙏.
Try this:
app.route('/addAnimal')
.get(function (req, res) {
res.sendFile('index.html', {root: 'project1'})
})
.post(function (req, res) {
data.push(req.body);
res.send('done'); // send response
});
Change the app.js code with the below.
/* Function to POST data */
const postData = async (url = "", data = {}) => {
const response = await fetch(url, {
method: "POST", // *GET, POST, PUT, DELETE, etc.
credentials: "same-origin", // include, *same-origin, omit
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(data) // body data type must match "Content-Type" header
});
try {
return response.json();
} catch (error) {
console.log("error", error);
// appropriately handle the error
}
};
// TODO-Call Function
(async function(){
let res = await postData("/addAnimal", { animal: "lion" });
console.log(res);
})();
And also change the post method like below.
app.route('/addAnimal')
.get(function (req, res) {
res.sendFile('index.html', {root: 'project1'})
})
.post(function (req, res) {
data.push(req.body);
res.status(200).send(data);
})
SOLVED, see my answer below
My server runs on localhost:3000
I develop on localhost:4200
I am creating something and trying to post it on an Amazon API
Angular side code:
sendSomething(something) {
const body = JSON.stringify(something);
// const headers = new Headers({'Content-Type': 'application/json'});
const headers = new Headers({'Access-Control-Allow-Origin': '*'});
return this.http.post('http://Amazon-API:port/send', body, {headers: headers})
.map((response: Response) => response.json())
.catch((error: Response) => {
this.error.handleError(error.json());
return Observable.throw(error.json());
});
}
Server side:
//////////////app.js//////////////
app.use(cors());
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", '*'); //<-- you can change this with a specific url like http://localhost:4200
// res.header("Access-Control-Allow-Credentials", true);
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
res.header("Access-Control-Allow-Headers", 'Origin,X-Requested-With,Content-Type,Accept,content-type,application/json');
next();
});
app.use('http://Amazon-API:port', engineRoutes);
//////////////routes/engine.js//////////////
router.post('/send', engine_controller.send_something);
//////////////controllers/engine.controller.js//////////////
exports.send_something = function (req, res, next) {
const somethingID = req.body.something;
Something.findById(somethingID, function(err, something) {
if (err) {
res.status(404).json({
title: 'Something not found',
error: {message: 'Something went wrong'}
});
}
console.log(something);
if (something) {
res.status(200).json({
message: 'Something successfully sent',
something: something
});
}
})
};
I have tried posting to that API with cors, without cors and with the res.headers appended, and every other variation I could think of
I still get this error which I've seen so common around here, but still, their solutions don't seem to work for me. Still getting this error...
Failed to load http://Amazon-API:port/send: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:4200' is therefore not allowed access. The response had HTTP status code 403.
That's from NETWORK tab:
Accept:*/*
Accept-Encoding:gzip, deflate
Accept-Language:he-IL,he;q=0.9,en-US;q=0.8,en;q=0.7
Access-Control-Request-Headers:access-control-allow-origin
Access-Control-Request-Method:POST
Connection:keep-alive
Host:Amazon-API:port
Origin:http://localhost:4200
Any kind of help would be so much appreciated
I see you added this code but I can't post comment yet, you may try to add this code before other routes
app.use(function (req, res, next) {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Headers', 'Origin, X-Requested-With,
Content-Type, Accept');
res.setHeader('Access-Control-Allow-Methods', 'POST, GET, PATCH, DELETE,
OPTIONS');
next();
});
Solved,
What I did was routing back to the server on the front:
sendSomething(something) {
const body = JSON.stringify(something);
const headers = new Headers({'Content-Type': 'application/json'});
return this.http.post('http://localhost:3000/api/somethings/send-something', body, {headers: headers})
.map((response: Response) => response.json())
.catch((error: Response) => {
this.error.handleError(error.json());
return Observable.throw(error.json());
});
}
And then accepting this route as it is on the back:
//////////////app.js//////////////////
app.use('/api/somethings/send-something', engineRoutes);
/////////////routes/engine.js/////////
router.post('/', engine_controller.send_something);
And most importantly, in the controller itself I used the newly downloaded request lib to send my json data to my external API:
////////////controlllers/engine.controller.js////////////
const request = require('request');
exports.send_something = function (req, res, next) {
const SomethingID = req.body.something;
Something.findById(SomethingID, function(err, something) {
if (err) {
res.status(404).json({
title: 'Something not found',
error: {message: 'Something went wrong'}
});
}
request({
url: app.get('amazon-API:port/method'),
method: "POST",
json: something
}, function (error, response, body) {
// console.log(error) <--- returns null or error
// console.log(response.statusCode <--- returns 200 / 403 / w.e
// console.log(body) <--- returns response pure html
res.status(200).json({
message: 'Something successfully sent',
response: body,
status: response.statusCode
});
});
})
};
Now as a response I'm getting what the server which I posted to sends me back, which is exactly what I need.
Ultimately I figured my way thanks to many other questions posted here
So thank you SOF once again!
Here is my get function in my message.service
message.service.ts
addMessage(message: Message) {
const body = JSON.stringify(message);
const headers = new Headers({ 'Content-Type': 'application/json' });
return this.http.post('http://localhost:3000/messages', body, { headers: headers })
.map((response: Response) => {
const result = response.json();
const message = new Message(result.obj.title, result.obj.content, 'Dummy', result.obj._id, null);
this.messages.push(message);
return message;
})
.catch((error: Response) => Observable.throw(error.json()));
}
And here is in my backend. If the user is not loggedin. It will return an error (Unauthorized).
routes/messages.js
router.use('/', (req, res, next) => {
jwt.verify(req.query.token, 'secret', (err, decoded) => {
if (err) {
return res.status(401).json({
title: 'Not Authenticated',
error: err
});
}
next();
});
});
And some posts says that it's related to CORS.
But I have this on my backend too.
app.js
app.use((req, res, next) => {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
res.setHeader('Access-Control-Allow-Methods', 'POST, GET, PATCH, DELETE, OPTIONS');
next();
});
app.use('/messages', messageRoutes);
app.use('/users', userRoutes);
app.use('/api', appRoutes);
And this is in my component.
message-input.component.ts
this.messageService.addMessage(message)
.subscribe(
data => this.snackBar.open('Your message is added!', 'Success!', {duration: 3000, extraClasses: ['success-snackbar']}),
error => console.error(error)
);
When there's an error because of authorization. The error is not the one I return from my backend. Instead it's this "Progress Event"
ProgressEvent {isTrusted: true, lengthComputable: false, loaded: 0, total: 0, type: "error", …}
I want to know how to show the error from my backend in json format. The error that should show to my console log.