Response for preflight has invalid HTTP status code 404 angular js - javascript

I am trying to prepare a Delete request in AngularJS to a nodeJS local server:
this.deleteMusician = function(id) {
$http({
url: 'http://localhost:3000/musicians/' + id,
method: "DELETE",
data: {}
//processData: false,
//headers: {'Content-Type': 'application/x-www-form-urlencoded'}
}).success(function (data, status, headers, config) {
console.log(data);
}).error(function (data, status, headers, config) {
console.log(data);
});
};
And my nodeJS route looks like this:
app.delete('/musicians/:id', musicians.delete);
The same request via PostMan works, but on Google Chrome i get:
OPTIONS http://localhost:3000/musicians/5628eacaa972a6c5154e4162 404 (Not Found)
XMLHttpRequest cannot load http://localhost:3000/musicians/5628eacaa972a6c5154e4162. Response for preflight has invalid HTTP status code 404
CORS is enabled:
var allowCrossDomain = function(req, res, next) {
// Website you wish to allow to connect
res.setHeader('Access-Control-Allow-Origin', 'http://localhost');
// 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', '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();
};
app.use(allowCrossDomain);

You will need to configure your node server to expect options method too.Check this other answer
so:
app.options('/musicians/:id', optionsCB);
and:
exports.optionsCB = function(req, res, next) {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'DELETE');
res.header('Access-Control-Allow-Headers', 'X-Requested-With,Content-Type');
next();
}

Related

NodeJS and ReactJS: Cookies do not set in browser

I am trying to send cookies in axios request from request handled in node js, NodeJS Does send cookies in response header but does not set in browser.
ReactJS
axios.post('http://localhost:4000/api/v1/auth/mflogin', {
data: wrapper,
},
)
.then((response) => {
setUser(true);
console.log(response.data);
navigate('/home');
})
.catch((error) => {
console.log('Error adding note.', error);
navigate('/countertwo');
});
This my backend:
One
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', 'http://localhost:8080');
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Authorization');
res.header('Access-Control-Allow-Credentials', true);
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS, HEAD');
res.header('Allow', 'GET, POST, PUT, DELETE, OPTIONS, HEAD');
res.header('X-Powered-By', '');
next();
});
app.options('*', cors()) // include before other routes
const candidateAuth = require('./routes/Candidate/auth');
app.use('/api/v1/auth/', candidateAuth);
Two
if (validPassword) {
assign(User.dataValues, { Verified: true });
response.cookie('BasicCookie', 'BasicCookie',{httpOnly: true, sameSite: 'strict', secure: 'true',maxAge:1000000000000 }).status(201).json({
User,
});
} else {
response.status(400).json({ error: "Invalid Password" });
}
But it does send cookie to post man request,
But it does come in response header but do not set in cookies?
Any to help me here??

How to Form Authentication Header for Axios Request to Node.js App Using Passport Local Authentication?

I have a node.js app and am developing a separate single page app (that will eventually be converted into Android and iOS native apps). I'm setting up an API on the node.js app and am struggling with authentication. The node.js app is using passport-local-mongoose for authentication and I store user data in a MongoDB backend. For testing/dev, the single page app is running on http://localhost:1234/.
My endpoint looks like:
exports.getDevicesAPI = async (req, res) => {
res.header('Access-Control-Allow-Origin', req.headers.origin);
res.header('Access-Control-Allow-Methods', 'GET, POST');
res.header('Access-Control-Allow-Headers: Authorization');
const devices = await Device.find({ owner: req.user._id });
res.json(devices);
};
I can GET this no problem with something like:
const axios = require('axios');
const url = 'http://localhost:7777/api/devices';
function getDevices() {
axios
.get(url)
.then(function(response) {
console.log(response);
})
.catch(function(error) {
console.log(error);
});
}
I want to add authenticate = passport.authenticate('header', {session: false, failWithError: true}); on the server side to provide authentication, but the following gives me Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:7777/api/devices. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing):
const axios = require('axios');
const url = 'http://localhost:7777/api/devices';
const username = myUsername;
const password = myPassword;
const axiosConfig = {
headers: {
'Content-Type': 'application/json',
},
Authorization: {
username,
password,
},
};
function authenticate() {
axios
.post(url, axiosConfig)
.then(function(response) {
console.log('Authenticated');
})
.catch(function(error) {
console.log('Error on Authentication');
});
}
Routes (for testing):
router.get('/api/devices', catchErrors(deviceController.getDevicesAPI));
router.post('/api/devices', catchErrors(deviceController.getDevicesAPI));
What am I missing?
You are having issues with CORS(Cross-Origin Resource Sharing) Restrictions. Read more about CORS here.
I believe this part of your code is meant to handle the CORS:
exports.getDevicesAPI = async (req, res) => {
// ...
res.header('Access-Control-Allow-Origin', req.headers.origin);
res.header('Access-Control-Allow-Methods', 'GET, POST');
res.header('Access-Control-Allow-Headers: Authorization');
// ...
};
However, the mistake here is that the setting of these CORS headers is tied to a route, i.e the getDevicesAPI route which is not supposed to be. For requests that are likely to modify resources in another origin(e.g the POST to getDevicesAPI route), the browser would first send a preflight request with the OPTIONS Http method before sending the actual request, the response to the preflight request is where the necessary CORS response-headers is expected to be set. You can find explanations on preflight requests here.
I would typically add a middleware like this above the other routes:
router.all('*', (req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'PUT, GET, POST, DELETE, OPTIONS');
res.header('Access-Control-Allow-Headers', '*');
next();
});

Why isn't my Fetch request sending custom headers in React-Native?

I am calling a fetch request akin to this.
fetch('https://api-endpoint.com/api',
{
method: "POST",
headers: new Headers({
'custom-header': 'custom header value'
})
}
)
.then(res=>{
/* code */
})
.catch(err=>{
/* code */
})
But it seems that the header is not being sent to the server. The server runs on Node.js, and I am attempting to reach it with React-Native.
I have allowed "access-control-allow-origin": "*" on the server, but to no avail.
I can also reach other endpoints on the server that don't require any headers.
And lastly, I have set the headers with both new Headers() and as an object.
What exactly am I missing to allow the headers to be sent? Is there a way to see exactly what is going on with my request in react-native?
It works in postman just fine.
EDIT:
I am using the cors middleware in my server.
app.use(cors())
appConfig.init(app);
Can you add these lines before using routes and try?
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
res.header(
"Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept, Authorization, custom-header"
);
res.header("Access-Control-Expose-Headers", "custom-header");
next();
});
And if you are using express cors middleware, you can add allowedHeaders and exposedHeaders options.
https://github.com/expressjs/cors#configuration-options
note if these configuration replaces the default headers, you may need to add the default headers to the options.
app.use(
cors({
exposedHeaders: ["custom-header"],
allowedHeaders: ["custom-header"]
})
);
Lastly you had better to use fetch api like this to send headers:
fetch('https://api-endpoint.com/api',
{
method: "POST",
headers: {
"custom-header": "custom header value"
}
}
)
.then(res => {
/* code */
})
.catch(err => {
/* code */
})
https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch
Be sure,you added the header in:
res.header(
"Access-Control-Allow-Headers",
"Your_OWN_header,...."
);

Unable to use 3rd party APIs getting error as No 'Access-Control-Allow-Origin' header is present on the requested resource

I am trying to hit 3rd party api using angularjs as shown below
Only in chrome I was able to see this issue and IE works perfectly
I got the error as...
XMLHttpRequest cannot load https://api.forecast.io/forecast/2c56930e3e0117b9943b9f618acfe981/17.3434321,78.536526. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access.
:3000/#/home:1 XMLHttpRequest cannot load https://www.w3schools.com/angular/customers.php. 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:3000' is therefore not allowed access.
homeController.js:23 failure
:3000/#/home:1 XMLHttpRequest cannot load http://www.w3schools.com/angular/customers.php. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access.
Angular JS code is:
angular.module('homeModule', []).
controller('HomeCtrl', ['$scope','$http'
, function($scope,$http ){
$http.get("http://www.w3schools.com/angular/customers.php").then(function (response) {
$scope.test1 = response.data.records;
});
$http.get("https://api.forecast.io/forecast/2c56930e3e0117b9943b9f618acfe981/17.3434321,78.536526").then(function (response) {
$scope.test2 = response;
});
$http({
method: 'GET',
url: "https://www.w3schools.com/angular/customers.php",
headers: {
'Access-Control-Allow-Origin': '*'
}
}).
success(function(status) {
$scope.test3 = response;
}).
error(function(status) {
console.log("failure");
});
}])
and My server.js is
var express = require('express'),
http = require('http');
var app = express();
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();
});
app.use(express.static(__dirname + '/public'))
.use('/node_modules', express.static(__dirname + '/node_modules'));
http.createServer(app).listen(3000, function () {
console.log("Server ready at http://localhost:3000");
});
First thing, you're requesting data from 3rd party servers. NOT your server. So setting headers and access control information on your server is not going to change anything.
The only workaround you can use here is to use padded JSON.
In angular, you'll need to use $http.jsonp and not $http.get.
Change your code to
$http.jsonp("http://www.w3schools.com/angular/customers.php").then(function (response) {
$scope.test1 = response.data.records;
});
$http.jsonp("https://api.forecast.io/forecast/2c56930e3e0117b9943b9f618acfe981/17.3434321,78.536526").then(function (response) {
$scope.test2 = response;
});
EDIT:
Forgot to mention callback setting in case of JSONP requests.
You'll need to specify a callback parameter as ?callback=JSON_CALLBACK in your URLs.
Change your code to
$http.jsonp("http://www.w3schools.com/angular/customers.php?callback=JSON_CALLBACK").then(function (response) {
$scope.test1 = response.data.records;
});
$http.jsonp("https://api.forecast.io/forecast/2c56930e3e0117b9943b9f618acfe981/17.3434321,78.536526?callback=JSON_CALLBACK").then(function (response) {
$scope.test2 = response;
});
And it should work.
EDIT 2:
As per the suggestion from avck, the above method is not only bad but also it involves security risks.
The right way to do this is as follows.
You're gonna have to change YOUR server.
First do,
npm install request
Then in your server.js
var express = require('express'),
http = require('http'),
request = require('request');
var app = express();
/* This is not needed
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();
});
*/
app.get('/getDataFromW3Schools', function(req, res, next){
var url = 'http://www.w3schools.com/angular/customers.php';
request(url, function (error, response, body) {
if (!error && response.statusCode == 200) {
console.log(body);
res.json(body);
}
});
});
app.get('/getDataFromForecast', function(req, res, next){
var url = 'https://api.forecast.io/forecast/2c56930e3e0117b9943b9f618acfe981/17.3434321,78.536526';
request(url, function (error, response, body) {
if (!error && response.statusCode == 200) {
console.log(body);
res.json(body);
}
});
});
app.use(express.static(__dirname + '/public')).use('/node_modules', express.static(__dirname + '/node_modules'));
http.createServer(app).listen(3000, function () {
console.log("Server ready at http://localhost:3000");
});
And in your client side, you'll have to do,
$http.get("/getDataFromW3Schools").then(function (response) {
$scope.test1 = response.data.records;
});
$http.get("/getDataFromForecast").then(function (response) {
$scope.test2 = response;
});
PLEASE NOTE: Now we're using $http.get.

Making CORS Request in Node.js/Express and AngularJS

I have seen many answers in stack overflow which says setting response headers will make you "CORS" request.But no solution worked for me.I have written the following code:
//Server.js Code
var express = require('express'),
app = express();
app.all('*',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-Credentials', true);
res.setHeader('Access-Control-Allow-Methods', 'POST, GET, PUT, DELETE, OPTIONS');
next();
I am trying to access the content from the URL using $http in client side:
//Controller.js
$http.get('http://domainA.com/a/ipadapi.php?id=135&client=ipad').success(function(response){
alert("I got response");
});
It's showing the following error in console.
XMLHttpRequest cannot load http://domainA.com/a/ipadapi.php?id=135&client=ipad The 'Access-Control-Allow-Origin' header has a value 'http://example.xxxxx.com' that is not equal to the supplied origin. Origin 'http://localhost:3000' is therefore not allowed access.
Note:I am new to nodeJS,Express and AngularJs
When you are passing credentials with CORS, you need to lock down the accepted origins. Try changing your origins from * to "localhost:3000"
See cross origin resource sharing with credentials
Change the header info from
res.setHeader("Access-Control-Allow-Origin", "*");
TO
res.header('Access-Control-Allow-Origin', 'http://localhost:3000');
If you're not the owner of domainA then you cannot send CORS headers from that domain. You can use your Node server as middleware, and proxy the request from your server to domainA. Your server can send CORS headers back to your angular app. pseudo code with hapi and needle:
import Hapi from 'hapi'
import needle from 'needle'
const server = new Hapi.Server()
server.connection({
port: 9090
, routes: {
cors: true
}
})
const handler = (req, reply) => {
const url = 'https://domainA.com'
, data = {
body: 'code'
}
needle.post(url, 'body=${data.body}', function(err, res) {
let json = JSON.parse(res.body)
reply(json.data)
})
}
server.route({
method: 'GET',
path: '/route/{id}',
handler: handler
}
)
server.start( err => {
if( err ) {
console.error( 'Error was handled!' )
console.error( err )
}
console.log( 'Server started at ${ server.info.uri }' )
})

Categories