I am using Facebook API for login in my react app. Frontend is reactJS and backend is nodeJS.
On first login I'm sending name, email and profile photo url to nodeJS. Prolem is that the nodeJS doesn't parse the url in proper way, even though it was sent properly form reactJS (using POST).
It looks like this:
{'{"name":"testname","email":"test#mail.com","profilePhoto":"https://platform-lookaside.fbsbx.com/platform/profilepic/?asid': '1111111111111111', height: '50', width: '50', ext: '1111111111', hash: 'AeRNlZmAF4w5mT5r"}' }
Should look like this:
{"name":"testname","email":"test#mail.com","profilePhoto":"https://platform-lookaside.fbsbx.com/platform/profilepic/?asid=1111111111111111&height=50&width=50&ext=1111111111&hash=ArS0tErHD8Tg9l3s"}"
So in other words it shouldn't split the url to parts, because i want to have the original url in database.
Here is the server.js
const express = require("express");
const config = require("../config");
const knex = require("../knex/knex");
const api = require("./api");
const cors = require("cors");
const bodyParser = require("body-parser");
const app = express();
app.use(cors());
app.use((req, res, next) => {
res.header("Access-Control-Allow-Origin", "*");
res.header(
"Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept"
);
next();
});
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use("/api", api.router);
app.listen(config.port, config.host, () => {
console.log(Server is running on http://${config.host}:${config.port});
});
and this is apiRequest.js in reactJS:
const apiRequest = (apiPath, options) => {
const mainOptions = {
headers: {
Accept: "application/json"
},
mode: "cors",
credentials: "include"
};
const finalOptions = merge(mainOptions, options);
if (finalOptions.body) {
finalOptions.body = JSON.stringify(finalOptions.body);
finalOptions.headers["Content-Type"] = "application/x-www-form-urlencoded";
}
const requestUrl = `http://${backendConfig.host}:${
backendConfig.port
}/api/${apiPath}`;
console.log(requestUrl, finalOptions);
return fetch(requestUrl, finalOptions).then(response =>
solveErrors(response)
);
};
Is this approach good or is there a better way to store url in database?
Solved it!
I removed credentials: "include" and changed "application/x-www-form-urlencoded" to "application/json"
Related
This is my node,js API,that works with no problems using postman, but when I try to make a request from a different origin like a react project the request is blocked
const express = require('express');
const mongoose = require('mongoose');
const app = express();
const port = process.env.PORT || 9000;
const routes = require('./routes/routes');
const token = require('./config/config');
const cors = require('cors')
app.use(cors())
app.use(express.json());
app.use('/api', routes);
app.listen(port, () => console.log('server listening on port', port));
const url = "mongodb://localhost/titles_db";
mongoose.connect(url,{})
.then( () => console.log('DB connected'))
.catch( (e) => console.log('Erorr on db connection'));
and this is the function that is called on my request
searchTitles = (req, res) => {
const terms = req.query.terms;
const format = req.query.format;
titleSchema.find({title: {$regex:terms, $options: 'i'}})
.then( data => {
if(format == 'json')
res.json(data);
else{
res.setHeader("Content-Type", "text/plain");
res.send(data);
}
})
.catch( error => res.json( {message: error}))
}
and here is the function that makes the request on the frontend
const getFieldText = e => {
setTerm({term: e.target.value });
const url = `http://localhost:9000/api/titles/?terms=${e.target.value}&format=json`
fetch(url)
.then(response => console.log(response))
.then(data => console.log(data));
}
even including cors library on node
const cors = require('cors')
app.use(cors())
I get this response
Response { type: "cors", url: "http://localhost:9000/api/titles/?terms=aaaaaa&format=json", redirected: false, status: 403, ok: false, statusText: "Forbidden", headers: Headers, body: ReadableStream, bodyUsed: false }
I added an options array but I have the same result
var corsOptions = {
origin: 'http://localhost:3000',
optionsSuccessStatus: 200 // some legacy browsers (IE11, various SmartTVs) choke on 204
}
app.use(cors(corsOptions))
configure the cross headers like this (in your server node config):
app.use(function (req, res, next) {
// Website you wish to allow to connect
res.setHeader('Access-Control-Allow-Origin', "http://localhost:8080");
// Request methods you wish to allow
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
// Request headers you wish to allow
res.setHeader('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, authorization, Access-Control-Allow-Origin');
// 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();
});
I have installed cors via npm and used the app.use(cors());middleware, but it is not solving my issue. I am running my frontend React App on Port localhost:3000
Access to XMLHttpRequest at 'http://localhost:3087/authenticate-token' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Here below is the whole code from my app.js file:
const bodyParser = require("body-parser");
const cors = require("cors");
const dotenv = require("dotenv");
const express = require("express");
const mongoose = require("mongoose");
const session = require("express-session");
// const request = require('req')
const app = express();
dotenv.config();
// Parse Application/json
app.use(bodyParser.json());
// Base URL
// app.locals.baseURL = "h";
app.use(cors());
app.use(
session({
secret: process.env.ACCESS_TOKEN_SECRET,
saveUninitialized: true,
resave: false,
cookie: {
secure: true,
},
})
);
// DB Config
const db = require("./config/keys").mongoURI;
// Connect to MongoDB
mongoose
.connect(db, {
useNewUrlParser: true,
useUnifiedTopology: true,
})
.then(() => console.log("MongoDB Connected"))
.catch((err) => console.log(err));
// Routes
app.use("/", require("./routes/auth"));
app.use("/pages", require("./routes/pages"));
app.use("/signUpModule", require("./routes/signUpModule"));
app.use("/users", require("./routes/users"));
const PORT = process.env.PORT || 3087;
app.listen(PORT, console.log(`Server running on ${PORT}`));
Below I have added the code from my end point:
const express = require("express");
// Authenticate Token
router.get(
"authenticate-token",
authFunctions.authenticateToken,
(req, res) => {
res.send({user: req.user, tokenValid: true});
);
Try to add this to your app.js file:
app.use((req, res, next) => {
res.header("Access-Control-Allow-Origin", "*");
res.header(
// "Access-Control-Allow-Origin",
"Origin, X-Requested-With, Content-Type, Accept, Authorization"
);
if (req.method == "OPTIONS") {
res.header("Access-Control-Allow-Methods", "GET PATCH DELETE POST PUT");
return res.status(200).json({});
}
next();
});
So, it so happens that the issue was coming from the client-side where I was using axio to make a request. At first I had the following:
export const userAuthenticated = async (token) => {
const response = await axios.get(`${API_BASE_URL}/authenticate-token`, {
headers: {
authorization: token,
}
});
if (response.statusText === "OK") return response.data;
};
Then later, I changed to the following, which worked:
export const userAuthenticated = async (token) => {
const response = await axios({
headers: {
authorization: token,
},
method: "get",
url: `${API_BASE_URL}/authenticate-token`,
});
if (response.statusText === "OK") return response.data;
};
I'm sending post request from "angular->port 4200" to "expressjs server->port 8000".
As an example i'm folowing this example: https://github.com/kuncevic/angular-httpclient-examples/blob/master/client/src/app/app.component.ts
I'm getting two error :
1)undefined from Nodejs(data and req.body.text)
2)Message received from background. Values reset
Angular side:
callServer() {
const culture = this.getLangCookie().split("-")[0];
const headers = new HttpHeaders()
headers.set('Authorization', 'my-auth-token')
headers.set('Content-Type', 'application/json');
this.http.post<string>(`http://127.0.0.1:8000/appculture`, culture, {
headers: headers
})
.subscribe(data => {
});
}
expressjs side:
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
var path = require('path');
app.all("/*", function(req, res, next){
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, Content-Length, X-Requested-With');
next();
});
app.use( bodyParser.json() ); // to support JSON-encoded bodies
app.use(bodyParser.urlencoded({ // to support URL-encoded bodies
extended: true
}));
app.post('/appculture', function (req, res) {
var currentCulture = `${req.body.text} from Nodejs`;
req.body.text = `${req.body.text} from Nodejs`;
res.send(req.body)
})
app.listen(8000, () => {
console.log('server started');
})
Either you are not sending anything of there is no value in body.text
Try to console.log(req.body) instead of req.body.text.
Try to console.log(culture) and this.getLangCookie() on the client side to see if you are actually sending something.
You can also make use of the network tab in the browser to inspect the request that you are sending.
Angular side:
callServer() {
const culture = this.getLangCookie().split("-")[0];
const headers = new HttpHeaders()
headers.set('Authorization', 'my-auth-token')
headers.set('Content-Type', 'application/json');
this.http.get(`http://127.0.0.1:8000/appculture?c=` + culture, {
headers: headers
})
.subscribe(data => {
});
}
Nodejs side:
app.get('/appculture', function (req, res) {
currentCulture = req.query.c;
res.send(req.body)
})
I have created a simple server in node js to take the request from a react app.
But for the GET method there is no CORS error but whenever I do post, it gives me an error.
For the POST method to work, I have implemented in index.js file of the actions folder and it should hit the url from the server.js file.
index.js
import axios from 'axios';
export const GET_NAVBAR = "GET_NAVBAR";
export const LOGIN = "LOGIN";
export const BASE_API_URL = "http://localhost:3030";
export const GUEST_API_URL = "https://XXX.XXX.XXX.X:5443/wcs/resources/store/1";
export const getNavbar = () => {
return axios.get(BASE_API_URL + '/topCategory').then(res => {
return {
type: GET_NAVBAR,
payload: res.data.express.catalogGroupView
};
});
};
export const login = () => {
return axios.post(GUEST_API_URL + '/guestidentity', {}).then(res => {
console.log(res);
return {
type: LOGIN,
payload: {}
}
}).catch(e => {
console.log(e);
return {
type: LOGIN,
payload: {}
}
});
};
server.js
const express = require('express');
const cors = require('cors');
const bodyParser = require('body-parser');
const Client = require('node-rest-client').Client;//import it here
const app = express();
const helmet = require('helmet');
const morgan = require('morgan');
// enhance your app security with Helmet
app.use(helmet());
// use bodyParser to parse application/json content-type
app.use(bodyParser.json());
app.use(cors());
// log HTTP requests
app.use(morgan('combined'));
app.post('/guestidentity', (req, res) => {
var client = new Client();
// direct way
client.post("https://XXX.XXX.XXX.X:5443/wcs/resources/store/1/guestidentity", (data, response) => {
res.send({express: data});
});
});
const port = 3030;
app.listen(port, () => console.log(`Server running on port ${port}`));
I don't know where my code is getting wrong. Can anybody please help me to troubleshoot this issue. I would be grateful if someone could provide an insight or guide me a little. Thanks
For my part I used
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
It will accept from any * sources, you might want to change that later
In your server.js , add the following middleware.
var allowCrossDomain = function(req, res, next) {
res.header('Access-Control-Allow-Origin', 'http://localhost:3030/');
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
res.header('Access-Control-Allow-Headers', 'Content-Type');
next();
};
app.use(allowCrossDomain);
Here's the code:
res.status(400).send('{"test":1}');
This returns an empty response. This returns "test":
res.status(400).send('test');
Here's the only extension I'm using:
app.use(bodyParser.json({ limit: '50mb', type: 'application/*' }));
How do I make Express send JSON? I'm using Express 4.16.3 (latest version).
Edit, here's the whole file. I'm using Express as a proxy:
const express = require('express');
const path = require('path');
const qs = require('qs');
const bodyParser = require('body-parser');
const fetch = require('node-fetch');
const API_URL = 'https://api.example.com/';
const app = express();
app.set('json spaces', 2);
Error.stackTraceLimit = 100;
app.use(bodyParser.json({ limit: '50mb', type: 'application/*' }));
app.options(/\/api\/(.+)/, async (req, res) => {
res.writeHead(200, {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'POST, GET, PUT, DELETE, OPTIONS',
'Access-Control-Allow-Credentials': false,
'Access-Control-Max-Age': '86400',
'Access-Control-Allow-Headers': 'X-Requested-With, X-HTTP-Method-Override, Content-Type, Accept',
});
res.end();
});
app.all(/\/api\/(.+)/, async (req, res) => {
let url = API_URL + req.params[0];
if (Object.keys(req.query).length) {
url += `?${qs.stringify(req.query)}`;
}
const opts = {
method: req.method,
headers: {
'content-type': req.headers['content-type'] || 'application/json',
},
};
if (req.headers.authorization) {
opts.headers.authorization = req.headers.authorization;
}
if (req.method.toUpperCase() !== 'GET') {
opts.body = JSON.stringify(req.body);
}
res.setHeader('content-type', 'application/json');
try {
const result = await fetch(url, opts);
const data = await result.text();
res.status(result.status).send({"test":1});
} catch (err) {
res.status(500).send(err.message || err);
}
});
app.listen(9002, () => console.log('Server started.'));
It was a CORS issue. It worked after adding:
res.header('access-control-allow-origin', '*');
res.header('access-control-allow-headers', 'origin, x-requested-with, content-type, accept');
I don't know why it worked with a non-JSON string, but it was blocked if the response was JSON.
To let express pass json object you can try to use this:
app.use(express.json());