api proxy server not parsing data back to user CORS - javascript

I am trying to access an api but when I access it in the browser, I get a CORS error. To get around this problem I set up an api proxy server. When this proxy gets a html request it connects to the browser blocked api and pulls the data needed. I think there is a problem on the proxy server where it is also blocking CORS and that needs to be changed, I’m not so sure. When I call the proxy api it gets the data from the browser blocked api and logs it to the console but does not push it to the browser because of the error below.
1.How do I correct this error “Reason: CORS header 'Access-Control-Allow-Origin' missing”
2.Should I be doing this a different way?
Error
Data being logged on the server
Server routing code - app.js
const apiCallFromRequest = require('./Request')
const apiCallFromNode = require('./NodeJsCall')
const apiCallFromTEST = require('./test.js')
const http = require('http')
http.createServer((req, res) => {
if(req.url === "/test"){
let start_time = new Date().getTime();
apiCallFromTEST.callApi(function(response){
//console.log(JSON.stringify(response));
res.write(JSON.stringify(response));
console.log(response);
console.log("Request API Requested");
console.log('API Test Time:', new Date().getTime() - start_time, 'ms');
res.end();
});
API proxy rought code -test.js
var rp = require('request-promise');
const callExternalApiUsingRequest = (callback) => {
var options = {
uri: 'https://app.invoiceninja.com/api/v1/products',
headers: {
'X-Ninja-Token': 'APIKEY'
},
json: true // Automatically parses the JSON string in the response
};
rp(options)
.then(function (data) {
console.log(data);
return callback(data);
})
.catch(function (err) {
// API call failed...
});
}
module.exports.callApi = callExternalApiUsingRequest;
website side - Just a basic fetch request
function gotProductData(){
fetch('http://localhost:3000/test')
.then(function(response) {
return response.json();
})
.then(function(myJson) {
console.log(myJson);
});

Try to install "cors" package (npm install cors) and import to app.js :
const cors = require('cors');
Run that above routes:
app.use(cors())
More details:
https://www.npmjs.com/package/cors#installation

Related

how to get cookie in react passed from express js api (MERN stack)

I have an api in express js that stores token in cookie on the client-side (react). The cookie is generated only when the user logins into the site. For example, when I test the login api with the postman, the cookie is generated as expected like this:
But when I log in with react.js then no cookie is found in the browser. Looks like the cookie was not passed to the front end as the screenshot demonstrates below:
As we got an alert message this means express api is working perfectly without any error!!
Here is my index.js file on express js that includes cookie-parser middleware as well
require("dotenv").config();
const port = process.env.PORT || 5050;
const express = require("express");
const app = express();
const cors = require("cors");
const authRouter = require("./routes/auth");
var cookieParser = require('cookie-parser')
connect_db();
app.use(express.json());
app.use(cookieParser())
app.use(cors());
app.use("/" , authRouter);
app.listen(port , () => {
console.log("Server is running!!");
})
Code for setting up the cookie from express api only controller
const User = require("../models/user");
const jwt = require("jsonwebtoken");
const bcrypt = require('bcrypt')
const login = async (req, res) => {
const { email, password } = req.body;
try {
const checkDetails = await User.findOne({ email });
if (checkDetails) {
const { password: hashedPassword, token, username } = checkDetails;
bcrypt.compare(password, hashedPassword, function (err, matched) {
if (matched) {
res.cookie("token", token, { expires: new Date(Date.now() + (5 * 60000)) , httpOnly: true }).json({ "message": "You logged in sucessfully!" });
} else {
res.status(500).json({ "message": "Wrong password" });
}
});
} else {
res.status(500).json({ "message": "Wrong email" });
}
} catch (error) {
console.log(error.message);
}
}
Here is the react.js code that I am using to fetch data from api without using a proxy in package.json file
if (errors.length === 0) {
const isLogin = await fetch("http://localhost:5000/api/login", {
method: "POST",
body: JSON.stringify({ email, password }),
headers: {
"Content-Type": "application/json"
}
});
const res = await isLogin.json();
if(res) alert(res.message);
}
I want to get to know what is the reason behind this "getting cookie in postman but not in the browser". Do I need to use any react package?
The network tab screenshot might help you.
If I see in the network tab I get the same cookie, set among the other headers
To my understanding, fetch doesn't send requests with the cookies your browser has stored for that domain, and similarly, it doesn't store any cookies it receives in the response. This seems to be the expected behaviour of fetch.
To override this, try setting the credentials option when making the request, like so:
fetch(url, {
// ...
credentials: 'include'
})
or, alternatively:
fetch(url, {
// ...
credentials: 'same-origin'
})
You can read more about the differences between the two here.
I got my error resolved with two changings in my code
In front end just added credentials: 'include'
fetch(url, {
method : "POST"
body : body,
headers : headers,
credentials: 'include'
})
And in back end just replaced app.use(cors()); to
app.use(cors({ origin: 'http://localhost:3000', credentials: true, exposedHeaders: ['Set-Cookie', 'Date', 'ETag'] }))
That's it got resolved, Now I have cookies stored in my browser!!! Great. Thanks to this article:
https://www.anycodings.com/2022/01/react-app-express-server-set-cookie-not.html
during development i also faced same things, let me help you that how i solve it,
Firstly you use proxy in your react package.json, below private one:-
"private": true,
"proxy":"http://127.0.0.1:5000",
mention the same port on which your node server is running
Like:-
app.listen(5000,'127.0.0.1',()=>{
console.log('Server is Running');
});
above both must be on same , now react will run on port 3000 as usual but now we will create proxy to react So, react and node ports get connected on same with the help of proxy indirectly.
Now, when you will make GET or POST request from react then don't provide full URL, only provide the path on which you wants to get hit in backend and get response,
Example:-
React side on sending request, follow like this:-
const submitHandler=()=>{
axios.post('/api/loginuser',
{mobile:inputField.mobile,password:inputField.password})
.then((res)=>{
console.log(res);
})
.catch((err)=>{
console.log(err);
})
}
Node side where it will hit:-
app.post('/api/loginuser', async(req,res)=>{
//Your Code Stuff Here
res.send()
}
on both side same link should hit, it is very important
it will 100%.
don't forget to mention
on node main main where server is listening

Cors enabled but Still got this "Origin has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present "

I'm attempting to redirect the browser from the backend, but getting this cors error every time. In the backend, I used the CORS package, however, it appears that it did not work.
Here is client site of the code
useEffect(() => {
async function getData() {
try {
// The params get from the url.
const {
data
} = await axios.get(`http://localhost:5000/${url}`);
setDestination(data);
} catch (error) {
setError(error.message);
}
}
getData();
}, [url]);
useEffect(() => {
if (destination) {
window.location.replace(destination);
}
}, [destination]);
Here is server site of the code
// app.js
const express = require("express");
const cors = require("cors");
const app = express();
app.use(express.urlencoded({
extended: false
}));
app.use(express.json());
app.use(cors());
//redirect controller
exports.redirect = asyncErrorHandler(async(req, res, next) => {
const shortUrl = await urlSchema.findOne({
shortUrl: req.params.shortUrl
});
if (!shortUrl) {
return next(new ErrorHandler("Invalid URL", 404));
}
const url = shortUrl.fullUrl;
res.redirect(url);
});
The server side code you've shown us, while CORS enabled, redirects to another URL.
When redirecting both the redirect response and the response to the subsequent request must grant permission with CORS.
You can't trick the browser into giving your JavasScript access to http://third-party.example.com/ (which isn't CORS enabled) by making a request to http://mine.example.net/ (which is) and redirecting to http://third-party.example.com/.

'Cannot set headers after they are sent to the client' error received after attempted to serve new html file

I'm very new to NodeJS, and I'm trying to follow/build off of a sample project built with the Spotify API and Express. The user is prompted to authenticate on the home page, and then I want to have them land at a different html file where relevant information will be displayed from the API. To my understanding "app.get" specifies what should happen once that endpoint is navigated to, so I thought that when my client.js file gets '/nextfile', I would present it with a new html file for that endpoint with response.sendFile(__dirname + '/views/nextpage.html'); within app.get('/nextpage').
Obviously, this isn't correct, because when I run the server, it simply returns to the index.html file after authentication, with an error that reads:
UnhandledPromiseRejectionWarning: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
I tried looking into this error, but I couldn't find anything that helped me solve my specific problem. Relevant excerpts from my client.js and server.js files are below:
Server.js
/** when home page is requested, respond with this file **/
app.get("/", function (request, response) {
response.sendFile(__dirname + '/views/index.html');
});
//-------------------------------------------------------------//
// init Spotify API wrapper
var SpotifyWebApi = require('spotify-web-api-node');
// Replace with your redirect URI, required scopes, and show_dialog preference
var redirectUri = 'http://localhost:8888/callback',
clID = '9013dc5d86b84ffca62df2f22e00968e',
clSEC = 'b9484118ab374707925b1b15100cc58b';
var scopes = ['user-top-read','streaming','user-read-private'];
var showDialog = true;
// The API object we'll use to interact with the API
var spotifyApi = new SpotifyWebApi({
clientId : clID,
clientSecret : clSEC,
redirectUri : redirectUri
});
app.get("/authorize", function (request, response) {
var authorizeURL = spotifyApi.createAuthorizeURL(scopes, null, showDialog);
console.log(authorizeURL)
response.send(authorizeURL);
});
// Exchange Authorization Code for an Access Token
app.get("/callback", function (request, response) {
var authorizationCode = request.query.code;
spotifyApi.authorizationCodeGrant(authorizationCode)
.then(function(data) {
console.log(data)
response.redirect(`/#access_token=${data.body['access_token']}&refresh_token=${data.body['refresh_token']}`)
}, function(err) {
console.log('Something went wrong when retrieving the access token!', err.message);
});
});
app.get("/logout", function (request, response) {
response.redirect('/');
});
app.get('/nextpage', function (request, response) {
**/* I want to serve his html file after the user is authenticated */**
response.sendFile(__dirname + '/views/nextpage.html');
var loggedInSpotifyApi = new SpotifyWebApi();
console.log(request.headers['authorization'].split(' ')[1]);
loggedInSpotifyApi.setAccessToken(request.headers['authorization'].split(' ')[1]);
// do stuff with the api
});
Client.js
$(function() {
$('#login').click(function() {
// Call the authorize endpoint, which will return an authorize URL, then redirect to that URL
$.get('/authorize', function(data) {
console.log(data)
window.location = data;
});
});
const hash = window.location.hash
.substring(1)
.split('&')
.reduce(function (initial, item) {
if (item) {
var parts = item.split('=');
initial[parts[0]] = decodeURIComponent(parts[1]);
}
return initial;
}, {});
window.location.hash = '';
if (hash.access_token) {
$.get({url: '/nextpage', headers: {"Authorization": `Bearer ${hash.access_token}`}}, function(data) {
// "Data" is the array of track objects we get from the API. See server.js for the function that returns it.
console.log(data)
var title = $('<h3>Your top tracks on Spotify:</h3>');
title.prependTo('#data-container-mod');
// For each of the tracks, create an element
data.items.forEach(function(track) {
var trackDiv = $('<li class="track"></li>');
trackDiv.text(track.name);
trackDiv.appendTo('#data-container ol');
});
});
}
});
Any help would be greatly appreciated.
The flow of your app in sending http headers appears to be like this from when the 'callback' url is reached at:-
A http header is sent alongside the redirect URL that contains the access token and refresh token.
Client.js takes the access token and sends it back through the /nextpage route with headers containing the access token
Send nextpage.html back to client.js and update the page accordingly..
What happens next?
Beware the browser tab still is on the route with the access tokens and refresh tokens.
So the jquery ajax request to '/nextpage' runs while the previous http headers had been sent already.
I however do not understand how the index.html is being returned..
can you try removing the window.location.hash=' ' in client.js

Failed to load resource: net::ERR_CONNECTION_REFUSED when fetching from localhost

I'm trying to make a request to my localhost server but am getting the error Failed to load resource: net::ERR_CONNECTION_REFUSED.
Here is my front end code:
(async () => {
const data = await fetch('http://localhost:8080/articles/', {
headers: { "Access-Control-Allow-Origin": "http://localhost:8080/articles/" }
});
const articles = await data.json()
console.log(articles)
})();
and backend code:
app.get("/articles/", function (req, res) {
let inputValue = req.body.page;
let pages = Math.ceil(totalResults / 10)
page = scripts.iteratePages(inputValue, page, pages);
request("https://newsapi.org/v2/top-headlines?q=" + initialQ +
"&category=sports&pageSize=10&page=" + page + "&sortBy=relevance&apiKey=" +
apiKey, function (error, response, body) {
if (!error && response.statusCode == 200) {
let data = JSON.parse(body);
let articles = scripts.articlesArr(data);
res.json({ articles: articles });
} else {
res.redirect("/");
console.log(response.body);
}
});
});
I've done some research myself, which points to using my private IP address instead of localhost and am getting an ... is not a function error in the console:
let ipAddress = "blah.blah.blah.blah"
(async () => {
const data = await fetch('http://' + ipAddress + ':8080/articles/', {
headers: { "Access-Control-Allow-Origin": "http://" + ipAddress + ":8080/articles/" }
});
const articles = await data.json()
console.log(articles)
})();
Any help would be great.
I think the error was caused by cross domain issues. You make a misunderstanding about CORS headers. The headers are not used by request but response.
If javascript program is making a cross domain request, the browser will first send an OPTION request with same parameters to the server. If backend on the server consider the request is legal, a response with only CORS headers will be send back to the browser, and then the browser check the CORS header against current environment. If CORS headers are suitable, the browser will finaly send the real request to server, or throw an error otherwise.
https://en.wikipedia.org/wiki/Cross-origin_resource_sharing

HTTP Post request not sending body or param data from ionic

HTTP post request is not sending body or param data to the server
Forgive me if this turns out to be a duplicate question. I've looked at several similar questions on stack overflow, but none of them have solved my problem. Also tried using a GET request instead of a POST request, but body data is still not sending.
Client side code:
// ionic code
homeUrl: string = 'http://localhost:80';
let obj = {"name": "Guest"};
let response = this.httpClient.post(this.homeUrl + '/admin-signup', JSON.stringify(obj));
response.subscribe(data => {
console.log('response: ', data);
//TODO: handle HTTP errors
});
Server side code:
server.post('/admin-signup', (req, res) => {
console.log('sign')
console.log(req.body);
// TODO: Process request
res
.status(200)
.send(JSON.parse('{"message": "Hello, signup!"}'))
.end();
});
First of all, import http client
import { HttpClient, HttpHeaders } from '#angular/common/http';
Then do the following
const header = new HttpHeaders({
'Content-Type': 'application/json',
Accept: 'application/json'
//api token (if need)
});
const options = {
headers: header
}
let response = this.httpClient.post(this.homeUrl + '/admin-signup', obj, options);
response.toPromise().then(data => {
console.log('response: ', data);
//TODO: handle HTTP errors
}).catch((err) =>{
console.log('error', err);
});
Hope it solve your problem.
I'm not familiar with ionic
but I'm guessing its a cors issue
can you try use cors?
const cors = require('cors');
app.use(cors());

Categories