Backbone model.destroy doesn't work but ajax delete call do - javascript

I currently have an issue with the destroy method of backbone.
This is my model:
var FavoritePlace = Backbone.Model.extend({
urlRoot: function() {
return 'http://localhost:3000/api/1.0/users/' + this.userId + '/places';
},
initialize: function(userId) {
this.userId = userId;
}
});
This is the function that tries to delete in my view:
var placeToRemove = userFavoritePlaces.get(place);
placeToRemove = new FavoritePlace({id : place.attributes.placeid});
placeToRemove.userId = user.attributes.id;
placeToRemove.destroy({
success: function() {
self.isFavorite(null);
}
});
userFavoritePlaces.remove(placeToRemove);
I create a new FavoritePlace with the id attribute otherwise my model is considered as new and it won't even do the call.
My webapp runs on localhost:63342
When I look at the network tab in Chrome developper tools I can see that the call is sent to this URL:
Request
URL:http://localhost:3000/api/1.0/users/8/places/2
The route server side looks like this:
router.delete('/users/:user_id/places/:place_id', function(req, res, next) {
dataQuery.userDeletePlaceFromFavorite(req, function(err, result) {
if (err) {
req.stats.error = err;
res.status(err.httpCode).json({error: err.error});
}
else {
res.json(result);
}
next();
})
});
I tried the same url in postman and it did work without any problems. Any idea why through Backbone it doesn't work ? Would it be related to any CORS headers or something alike ?
Thanks
// Edited
Details of the call from network tab
curl 'http://localhost:3000/api/1.0/users/8/places/2?apikey=2yIsVhfg' -X OPTIONS -H 'Access-Control-Request-Method: DELETE' -H 'Origin: http://localhost:63342' -H 'Referer: http://localhost:63342/cmweb/index.html' -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.107 Safari/537.36' -H 'Access-Control-Request-Headers: accept' --compressed
Details of the call from postman
Access-Control-Allow-Headers → X-Requested-With, origin, content-type, accept
Access-Control-Allow-Method → GET, POST, DELETE
Access-Control-Allow-Origin → *
Connection → keep-alive
Content-Length → 21
Content-Type → application/json; charset=utf-8
Date → Fri, 24 Jul 2015 17:35:31 GMT
Vary → Accept-Encoding
X-Powered-By → Express

I came across this other post: jQuery.ajax sending both OPTIONS and POST, how to handle with Express.js (Node.js) and it actually solved my problem.
My API was not answering correctly to the http options call made by my browser, so the DELETE call was never reaching my backend. The difference with Postman is that this option call is not made before the DELETE is send to the API. Now my backend respond with the proper headers to the options method and the DELETE call works exactly like in postman.
this is the code sample i added:
if (req.method === 'OPTIONS') {
console.log('!OPTIONS');
var headers = {};
// IE8 does not allow domains to be specified, just the *
// headers["Access-Control-Allow-Origin"] = req.headers.origin;
headers["Access-Control-Allow-Origin"] = "*";
headers["Access-Control-Allow-Methods"] = "POST, GET, PUT, DELETE, OPTIONS";
headers["Access-Control-Allow-Credentials"] = false;
headers["Access-Control-Max-Age"] = '86400'; // 24 hours
headers["Access-Control-Allow-Headers"] = "X-Requested-With, X-HTTP-Method-Override, Content-Type, Accept";
res.writeHead(200, headers);
res.end();
}

Related

CORS policy Issue, It works in local development, but it didn't work in deployed site

I'm having trouble with the CORS policy problem.
The project is very simple. I'm using the Sendgrid for sending e-mail.
I implemented frontend and backend for this tiny project. In backend, Sendgrid sending mail function is used.
I tested in local, it works fine. After I deployed the project, I got CORS issue.
This is the Error messages.
Access to fetch at 'https://mailsender-api.xxxxxx.xxx/sendmail' from origin 'https://mailsender-xxxxx.xxxxxx.xxx' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
POST https://mailsender-api.xxxxxx.xxx/sendmail net::ERR_FAILED
In frontend I separate fetch function
Fetch.tsx
export const fetchPost = async ({ endpoint, data }: any) => {
return fetch(`https://mailsender-api.xxxxxx.xxx/${endpoint}`, {
method: "POST",
body: JSON.stringify(data),
headers: {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*",
},
mode: "cors",
});
};
and different file calls the fetch function
const handleClick = async (
email: string,
subject: string,
intention: string
) => {
if (email === "" || intention === "") {
alert("Please fill out all fields");
} else if (!validateEmail(email)) {
alert("Invalid Email address");
} else {
const fetchOption = {
endpoint: `sendmail`,
data: {
email,
subject,
intention,
},
};
const result = await fetchPost(fetchOption);
if (result.ok) {
return history.push("/complete");
}
}
}
Below are backend code. I separate send mail function.
server.js
import cors from "cors";
import express from "express";
import { sendmail } from "./sendmail";
const router = express.Router();
const server = express();
server.use(
cors({
methods: ["GET", "POST", "OPTIONS"],
allowedHeaders: ["Content-Type", "Access-Control-Allow-Origin", "Accept"],
origin: "*",
credentials: true,
optionsSuccessStatus: 200, // some legacy browsers (IE11, various SmartTVs) choke on 204
})
);
server.use(express.json({ type: ["application/json"] })); // for parsing application/json
server.use(express.urlencoded({ extended: true })); // for parsing application/x-www-form-urlencoded
router.post("/sendmail", sendmail);
router.options("*", cors());
server.use(router);
server.listen(4000, function () {
console.log("app is listening");
});
export { router };
export default server;
when post requests comes in, sendmail function is invoked.
sendmail.js
import { sendScheduledMail } from "./config";
export const sendmail = async (req, res) => {
let data = {
address: req.body.email,
subject: req.body.subject,
content: req.body.intention,
};
try {
await sendScheduledMail(data.address, data.subject, data.content);
return res.end();
} catch (error) {
console.log(error);
}
};
Below is config.js file
import sgMail from "#sendgrid/mail";
import dotenv from "dotenv";
import "../.env";
dotenv.config();
export const sendScheduledMail = (address, subject, content) => {
let date = Math.round(new Date("June 29, 2020 12:37:00").getTime() / 1000);
let tempDate = Math.round(new Date().getTime() / 1000);
const email = {
from: "CBLM#CBLM.com",
to: address,
subject: subject,
html: `<p>${content}</p>`,
send_at: tempDate,
};
sgMail.setApiKey(process.env.SENDGRID_API_KEY);
return sgMail.send(email);
};
I deployed in Vercel.com. I asked about this problem, they said, it is codebase problem, so they have nothing to do. I searched for the solution, and I followed all they suggest, but it didn't work. Please help me.
------------------------UPDATED----------------------------------------
I deleted "Access-Control-Allow-Origin": "*", but it is not working.
I found out that Vercel has their own configure file ('now.json'). I added some headers, then I got something else.
now.json file
{
"routes": [
{
"headers": {
"Access-Control-Allow-Origin": "https://mailsender-delta.xxxxxx.xxx",
"Content-Type": "application/json",
"Access-Control-Allow-Methods": "POST, OPTIONS, HEAD",
"Access-Control-Allow-Headers": "Access-Control-Allow-Methods, Access-Control-Allow-Headers, Access-Control-Allow-Credentials, Access-Control-Allow-Origin, Content-Type",
"Access-Control-Allow-Credentials": "true"
},
"src": "/.*",
"dest": "/server.js"
}
]
}
I got POST https://mailsender-api.xxxxxx.xxx/sendmail net::ERR_ABORTED 405
Below is the request header
> General
Request URL: https://mailsender-api.xxxxxx.xxx/sendmail
Request Method: OPTIONS
Status Code: 204
Remote Address: 76.76.21.21:443
Referrer Policy: no-referrer-when-downgrade
> Response Headers
access-control-allow-credentials: true
access-control-allow-headers: Access-Control-Allow-Methods, Access-Control-Allow-Headers, Access-Control-Allow-Credentials, Access-Control-Allow-Origin, Content-Type
access-control-allow-methods: OPTIONS, GET, HEAD
access-control-allow-origin: *
cache-control: s-maxage=0
date: Fri, 03 Jul 2020 23:20:50 GMT
server: Vercel
status: 204
strict-transport-security: max-age=63072000; includeSubDomains; preload
x-vercel-cache: HIT
x-vercel-id: iad1::frndf-1593818450293-40ef1caa15b3
> Request Header
:authority: mailsender-api.xxxxxx.xxx
:method: OPTIONS
:path: /sendmail
:scheme: https
accept: */*
accept-encoding: gzip, deflate, br
accept-language: en-US,en;q=0.9,ko;q=0.8,la;q=0.7
access-control-request-headers: access-control-allow-credentials,access-control-allow-headers,access-control-allow-methods,content-type
access-control-request-method: POST
origin: https://mailsender-delta.vercel.app
referer: https://mailsender-delta.vercel.app/
sec-fetch-dest: empty
sec-fetch-mode: cors
sec-fetch-site: same-site
user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36
> General
Request URL: https://mailsender-api.xxxxxx.xxx/sendmail
Request Method: POST
Status Code: 405
Remote Address: 76.76.21.21:443
Referrer Policy: no-referrer-when-downgrade
> Response Headers
access-control-allow-credentials: true
access-control-allow-headers: Access-Control-Allow-Methods, Access-Control-Allow-Headers, Access-Control-Allow-Credentials, Access-Control-Allow-Origin, Content-Type
access-control-allow-methods: POST, OPTIONS, HEAD
access-control-allow-origin: https://mailsender-delta.vercel.app
cache-control: s-maxage=0
content-type: application/json
date: Fri, 03 Jul 2020 23:20:50 GMT
server: Vercel
status: 405
strict-transport-security: max-age=63072000; includeSubDomains; preload
x-vercel-cache: HIT
x-vercel-id: iad1::frndf-1593818450309-4f5547ab5464
> Request Headers
:authority: mailsender-api.xxxxxx.xxx
:method: POST
:path: /sendmail
:scheme: https
accept: */*
accept-encoding: gzip, deflate, br
accept-language: en-US,en;q=0.9,ko;q=0.8,la;q=0.7
access-control-allow-credentials: true
access-control-allow-headers: X-Requested-With, Content-Type, Accept
access-control-allow-methods: *
content-length: 88
content-type: application/json
origin: https://mailsender-delta.xxxxxx.xxx
referer: https://mailsender-delta.xxxxxx.xxx/
sec-fetch-dest: empty
sec-fetch-mode: cors
sec-fetch-site: same-site
user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36
I faced the same problem. The solution is available in the doc of vercel: https://vercel.com/support/articles/how-to-enable-cors .
In your node.js backend, create a file vercel.json and put the code there.
{
"headers": [
{
"source": "/api/(.*)",
"headers": [
{ "key": "Access-Control-Allow-Credentials", "value": "true" },
{ "key": "Access-Control-Allow-Origin", "value": "*" },
{ "key": "Access-Control-Allow-Methods", "value": "GET,OPTIONS,PATCH,DELETE,POST,PUT" },
{ "key": "Access-Control-Allow-Headers", "value": "X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version" }
]
}
]
}
It works for sure.

React connecting to Node Cors Preflight Failure

Node Server
var app = express();
app.use(function(req, res, next) {
res.header('Access-Control-Allow-Credentials', true);
res.header('Access-Control-Allow-Origin', req.headers.origin);
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
res.header('Access-Control-Allow-Headers', 'X-Requested-With, X-HTTP-Method-Override, Content-Type, Accept');
if ('OPTIONS' == req.method) {
res.send(200);
} else {
next();
}
});
React JS Fetch
function request(url, options) {
return fetch(url, options)
.then(checkStatus)
.then(parseJSON);
}
export function* login() {
const username = yield select(makeSelectUsername());
const password = yield select(makeSelectPassword());
const requestURL = 'http://myurlhere.com:1337/user/login/';
const requestOptions = {
method: 'POST',
mode: 'cors',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(
{username: username,
password: password}
)
}
try {
const result = yield call(request, requestURL, requestOptions);
yield put(loginApiCallSuccess(result));
} catch (err) {
yield put(loginApiCallFailure(err));
}
}
I need help determining what is wrong with my request or server side handling where chrome is cancelling my requests after preflight failure, aka why is my preflight request failing.
I am running the react on localhost and connecting to a remote server with a different url.
From what I can tell the preflight request is failing then chrome is cancelling the request. However when I ran the request locally the login was still hitting the login route on the node side successfully.
When stepping through the code I get a 400 error from the services on the actual call after the preflight call. If I run the call and don't step through I get a
(canceled) in the network tab of dev tools. However the call is successful on the server side each time.
General
Request URL:http://jenkins.murmillosoftware.com:1337/user/register/
Request Method:POST
Status Code:400 Bad Request
Remote Address:52.5.222.29:1337
Referrer Policy:no-referrer-when-downgrade
Response Headers
view source
Access-Control-Allow-Credentials:true
Access-Control-Allow-Headers:X-Requested-With, X-HTTP-Method-Override, Content-Type, Accept, Origin
Access-Control-Allow-Methods:GET,PUT,POST,DELETE
Access-Control-Allow-Origin:http://127.0.0.1:3000
Connection:keep-alive
Content-Length:47
Content-Type:application/json; charset=utf-8
Date:Wed, 16 Aug 2017 22:24:48 GMT
ETag:W/"2f-vn6Bxm14Gkpb5HFTCsgU2h3Nq3o"
set-cookie:connect.sid=s%3AjPVtqIoi6zy0QPmhfFkprFObfwj_J-Lw.sPvW3qRc1Vwj4R6qFBtW0oXykF68Qn%2FAwmLCWrg51qc; Path=/; HttpOnly
X-Powered-By:Express
Request Headers
view source
Accept:application/json
Accept-Encoding:gzip, deflate
Accept-Language:en-US,en;q=0.8
Cache-Control:no-cache
Connection:keep-alive
Content-Length:44
Content-Type:application/json
Host:jenkins.murmillosoftware.com:1337
Origin:http://127.0.0.1:3000
Pragma:no-cache
Referer:http://127.0.0.1:3000/login?
User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36
Request Payload
view source
{username: "fdasfas", password: "asdfasdf"}
password
:
"asdfasdf"
username
:
"fdasfas"
have you ever tried express/cors i recently also had problem with access allow origin then i download express/cors from
npm install cors
then add in your program
var express = require('express')
var cors = require('cors')
var app = express()
app.use(cors())
app.get('/products/:id', function (req, res, next) {
res.json({msg: 'This is CORS-enabled for all origins!'})
})
app.listen(80, function () {
console.log('CORS-enabled web server listening on port 80')
})
you can also see other method to use cors in [link]https://github.com/expressjs/cors

fetch OPTIONS return HTTP 401 while Curl Command succeeds

This is what my fetch code looks like
let getSummary = (year, month) => {
let url = baseUrl + "/rest/monthlySummaries/" +
localStorage.getItem("paUserId") + "/" + year + "/" + month;
let authHeaders = {
"Content-Type": "application/json",
"Accept": "application/json",
"Bearer": localStorage.getItem("paToken")
};
console.log("summary url:", url, ",headers:", authHeaders);
return fetch(url, {
method: "GET",
headers: authHeaders
});
};
Since this is GET request, browsers make preflight reqeusts using HTTP OPTIONS to make sure that they make indeed make HTTP GET requests. I log what call is made, I see
summary url: https://api.myapp.com/rest/monthlySummaries/userId/2017/4 ,headers: Object {Content-Type: "application/json", Accept: "application/json", Bearer: "41afa8432aaa411e48b6c1c637c77cb3:userId:84000000"}Accept: "application/json"Bearer: "41afa8432aaa411e48b6c1c637c77cb3:userId:84000000"Content-Type: "application/json"__proto__: Object
2VM50885:1 OPTIONS https://api.myapp.com/rest/monthlySummaries/cca6b151-cab4-4de2-81db-9a739a62ae88/2017/4 401 (Unauthorized)
While, when I do similar thing on curl, everything works
curl -v -X OPTIONS -H"BEARER:e3310afc4dcd68d80d56a83bddfd4a09:userId:564000000" "https://api.myapp.com/rest/monthlySummaries/userId/2017/4"
* Trying 52.23.254.96...
* Connected to api.myapp.com (52.23.254.96) port 443 (#0)
* TLS 1.2 connection using TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
* Server certificate: DigiCert SHA2 High Assurance Server CA
* Server certificate: DigiCert High Assurance EV Root CA
> OPTIONS /rest/monthlySummaries/userId/2017/4 HTTP/1.1
> Host: api.myapp.com
> User-Agent: curl/7.43.0
> Accept: */*
> BEARER:e3310afc4dcd68d80d56a83bddfd4a09:userId:564000000
>
< HTTP/1.1 200 OK
< Date: Mon, 29 May 2017 23:21:11 GMT
< Server: WildFly/8
< X-Powered-By: Undertow/1
< Access-Control-Allow-Headers: origin, content-type, accept, authorization
< Allow: HEAD, GET, OPTIONS
< Access-Control-Allow-Origin: *
< Access-Control-Allow-Credentials: true
< Content-Type: text/plain
< Content-Length: 18
< Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS, HEAD
< Access-Control-Max-Age: 1209600
< Vary: Accept-Encoding
<
* Connection #0 to host api.myapp.com left intact
Why the behavior is so different? What am I missing in fetch?
UPDATE
My server enables CORS support
#Provider
public class CORSFilter implements ContainerResponseFilter {
#Override
public void filter(ContainerRequestContext containerRequestContext,
ContainerResponseContext containerResponseContext) throws IOException {
containerResponseContext.getHeaders().add("Access-Control-Allow-Origin", "*");
containerResponseContext.getHeaders().add("Access-Control-Allow-Headers", "origin, content-type, accept, authorization");
containerResponseContext.getHeaders().add("Access-Control-Allow-Credentials", "true");
containerResponseContext.getHeaders().add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, HEAD");
containerResponseContext.getHeaders().add("Access-Control-Max-Age", "1209600");
}
}
This can be seen in the response as well
See where you have configured
.add("Access-Control-Allow-Headers", "origin, content-type, accept, authorization");
You haven't allowed the Bearer header, nor is it the correct way to pass a JWT.
You probably meant
"Authorization": `Bearer ${localStorage.getItem("paToken")}`
Sending Bearer when it isn't in the allowed headers list will fail the pre-flight validation.

Making a PUT request results in an OPTIONS request being sent first before the PUT, why does the browser behave this way?

When i send a POST request, it's ok. But when i send a PUT request (replace $http.post() to $http.put()) Angular send an OPTIONS request without datas, wait the response and send a PUT request with datas.
It's not a CORPS problem because it's the client which send 2 requests.
For the OPTIONS request, the JSON response isn't parsed because Angular doesn't go to the success function.
I want to Angular not send the OPTIONS request.
Do you know this problem ? Do you know a fix ?
The code :
var app = angular.module('myApp', []);
app.config(function($httpProvider) {
delete $httpProvider.defaults.headers.common['X-Requested-With'];
$httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8';
$httpProvider.defaults.headers.put['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8';
$httpProvider.defaults.useXDomain = true;
//
var param = function(obj) {
var query = '', name, value, fullSubName, subName, subValue, innerObj, i;
for(name in obj) {
value = obj[name];
if(value instanceof Array) {
for(i=0; i<value.length; ++i) {
subValue = value[i];
fullSubName = name + '[' + i + ']';
innerObj = {};
innerObj[fullSubName] = subValue;
query += param(innerObj) + '&';
}
}
else if(value instanceof Object) {
for(subName in value) {
subValue = value[subName];
fullSubName = name + '[' + subName + ']';
innerObj = {};
innerObj[fullSubName] = subValue;
query += param(innerObj) + '&';
}
}
else if(value !== undefined && value !== null) {
query += encodeURIComponent(name) + '=' + encodeURIComponent(value) + '&';
}
}
return query.length ? query.substr(0, query.length - 1) : query;
};
// Override $http service's default transformRequest (json to application/x-www-form-urlencoded)
$httpProvider.defaults.transformRequest = [function(data) {
return angular.isObject(data) && String(data) !== '[object File]' ? param(data) : data;
}];
});
app.controller('login', function ($scope, $http) {
$scope.run = function() {
var file_data = $("#file").prop("files")[0];
var datas = {email:"email#domain.com", pass:sha1("xxxxxx")};
$http.put("http://myapi.com/user/connect", datas
).success(function(data, status, headers, config) {
console.log(data);
}).error(function(data, status, headers, config) {
});
return;
}
});
The first request :
General
Remote Address:127.0.0.1:80
Request URL:http://api.wezit.local/user/connect
Request Method:OPTIONS
Status Code:200 OK
Response Headers
Access-Control-Allow-Methods:POST, GET, PUT, DELETE
Access-Control-Allow-Origin:*
Cache-Control:no-cache, must-revalidate
Connection:Keep-Alive
Content-Length:170
Content-Type:application/json;
Date:Fri, 17 Jul 2015 16:31:15 GMT
Expires:Mon, 26 Jul 1997 05:00:00 GMT
Keep-Alive:timeout=5, max=100
Pragma:no-cache
Server:Apache/2.4.10 (Fedora) PHP/5.5.25
Set-Cookie:PHPSESSID=2dj440b2vr2emi5ht9ojcl8gk6; path=/
Set-Cookie:PHPSESSID=q3pg80qb43ps6tpkljlvelo0k7; path=/
X-Powered-By:PHP/5.5.25
Request Headers
Accept:*/*
Accept-Encoding:gzip, deflate, sdch
Accept-Language:fr-FR,fr;q=0.8,en-US;q=0.6,en;q=0.4
Access-Control-Request-Headers:accept, content-type
Access-Control-Request-Method:PUT
Connection:keep-alive
Host:api.wezit.local
Origin:http://test.local
Referer:http://test.local/api.php
User-Agent:Mozilla/5.0 (X11; Linux i686 (x86_64)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.125 Safari/537.36
The second request :
General
Remote Address:127.0.0.1:80
Request URL:http://api.wezit.local/user/connect
Request Method:PUT
Status Code:200 OK
Response Headers
Access-Control-Allow-Methods:POST, GET, PUT, DELETE
Access-Control-Allow-Origin:*
Cache-Control:no-cache, must-revalidate
Connection:Keep-Alive
Content-Length:327
Content-Type:application/json;
Date:Fri, 17 Jul 2015 16:31:15 GMT
Expires:Mon, 26 Jul 1997 05:00:00 GMT
Keep-Alive:timeout=5, max=99
Pragma:no-cache
Server:Apache/2.4.10 (Fedora) PHP/5.5.25
Set-Cookie:PHPSESSID=18jfhgq2fs1p1f1nu7ua1ap8c3; path=/
Set-Cookie:PHPSESSID=14aifglpntf8amavkipclvom67; path=/
X-Powered-By:PHP/5.5.25
Request Headers
Accept:application/json, text/plain, */*
Accept-Encoding:gzip, deflate, sdch
Accept-Language:fr-FR,fr;q=0.8,en-US;q=0.6,en;q=0.4
Connection:keep-alive
Content-Length:142
Content-Type:application/x-www-form-urlencoded; charset=UTF-8
Host:api.wezit.local
Origin:http://test.local
Referer:http://test.local/api.php
User-Agent:Mozilla/5.0 (X11; Linux i686 (x86_64)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.125 Safari/537.36
Form Data
email:email#domain.com
pass:ce35927f4dcb044bceda5f385823419cb0156507
Browsers always make a pre-flight request with the OPTION method, when you initiate a cross-origin request. That means the API you are trying to access is on a different origin from your application. There's nothing you can do about this.
Do you know this problem?
There is no problem in what you observed, it is the expected behaviour.
When i send a POST request, it's OK.
Here's the reason why it's OK:
In particular, a request is preflighted if:
It uses methods other than GET, HEAD or POST. Also, if POST is used to send request data with a Content-Type other than
application/x-www-form-urlencoded, multipart/form-data, or text/plain,
e.g. if the POST request sends an XML payload to the server using
application/xml or text/xml, then the request is preflighted.
It sets custom headers in the request (e.g. the request uses a header such as X-PINGOTHER)

Access-Control-Allow-Origin and Angular.js $http

Whenever I make a webapp and I get a CORS problem, I start making coffee. After screwing with it for a while I manage to get it working but this time it's not and I need help.
Here is the client side code:
$http({method: 'GET', url: 'http://localhost:3000/api/symbol/junk',
headers:{
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type, X-Requested-With',
'X-Random-Shit':'123123123'
}})
.success(function(d){ console.log( "yay" ); })
.error(function(d){ console.log( "nope" ); });
The server side is a regular node.js with an express app. I have an extention called cors and it's being used with express this way:
var app = express();
app.configure(function(){
app.use(express.bodyParser());
app.use(app.router);
app.use(cors({origin:"*"}));
});
app.listen(3000);
app.get('/', function(req, res){
res.end("ok");
});
If I do
curl -v -H "Origin: https://github.com" http://localhost:3000/
It gets back with:
* Adding handle: conn: 0x7ff991800000
* Adding handle: send: 0
* Adding handle: recv: 0
* Curl_addHandleToPipeline: length: 1
* - Conn 0 (0x7ff991800000) send_pipe: 1, recv_pipe: 0
* About to connect() to localhost port 3000 (#0)
* Trying ::1...
* Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 3000 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.30.0
> Host: localhost:3000
> Accept: */*
> Origin: https://github.com
>
< HTTP/1.1 200 OK
< X-Powered-By: Express
< Date: Tue, 24 Dec 2013 03:23:40 GMT
< Connection: keep-alive
< Transfer-Encoding: chunked
<
* Connection #0 to host localhost left intact
ok
If I run the client side code, it brigs up this error:
OPTIONS http://localhost:3000/api/symbol/junk No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8000' is therefore not allowed access. angular.js:7889
XMLHttpRequest cannot load http://localhost:3000/api/symbol/junk. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8000' is therefore not allowed access. localhost/:1
nope
Checking Chromes headers:
Request URL:http://localhost:3000/api/symbol/junk
Request Method:OPTIONS
Status Code:200 OK
Request Headersview source
Accept:*/*
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8,es;q=0.6,pt;q=0.4
Access-Control-Request-Headers:access-control-allow-origin, accept, access-control-allow-methods, access-control-allow-headers, x-random-shit
Access-Control-Request-Method:GET
Cache-Control:max-age=0
Connection:keep-alive
Host:localhost:3000
Origin:http://localhost:8000
Referer:http://localhost:8000/
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36
Response Headersview source
Allow:GET
Connection:keep-alive
Content-Length:3
Content-Type:text/html; charset=utf-8
Date:Tue, 24 Dec 2013 03:27:45 GMT
X-Powered-By:Express
Checking the request headers I see that my test string X-Random-Shit is present in the "Access-Control-Request-Headers" but it's value is not there. Also, in my head I was expecting to see one line for each one of the headers I am setting, not a blob.
UPDATES ---
I changed my frontend to jQuery instead of Angular and made my backend like this:
var app = express();
app.configure(function(){
app.use(express.bodyParser());
app.use(app.router);
});
app.all('*', function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header('Access-Control-Allow-Methods', 'OPTIONS,GET,POST,PUT,DELETE');
res.header("Access-Control-Allow-Headers", "Content-Type, Authorization, X-Requested-With");
if ('OPTIONS' == req.method){
return res.send(200);
}
next();
});
app.get('/', function(req, res){
res.end("ok");
});
Now it works with GET but does not with anything else (PUT, POST..).
I'll see if any of you comes up with a solution. In the mean time in throwing the RESTful concept out the window and making everything with GETs.
I'm new to AngularJS and I came across this CORS problem, almost lost my mind! Luckily i found a way to fix this. So here it goes....
My problem was, when I use AngularJS $resource in sending API requests I'm getting this error message XMLHttpRequest cannot load http://website.com. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost' is therefore not allowed access. Yup, I already added callback="JSON_CALLBACK" and it didn't work.
What I did to fix it the problem, instead of using GET method or resorting to $http.get, I've used JSONP. Just replace GET method with JSONP and change the api response format to JSONP as well.
myApp.factory('myFactory', ['$resource', function($resource) {
return $resource( 'http://website.com/api/:apiMethod',
{ callback: "JSON_CALLBACK", format:'jsonp' },
{
method1: {
method: 'JSONP',
params: {
apiMethod: 'hello world'
}
},
method2: {
method: 'JSONP',
params: {
apiMethod: 'hey ho!'
}
}
} );
}]);
I hope someone find this helpful. :)
I've had success with express and editing the res.header. Mine matches yours pretty closely but I have a different Allow-Headers as noted below:
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
I'm also using Angular and Node/Express, but I don't have the headers called out in the Angular code only the node/express
Writing this middleware might help !
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();
});
for details visit http://enable-cors.org/server_expressjs.html
Adding below to server.js resolved mine
server.post('/your-rest-endpt/*', function(req,res){
console.log('');
console.log('req.url: '+req.url);
console.log('req.headers: ');
console.dir(req.headers);
console.log('req.body: ');
console.dir(req.body);
var options = {
host: 'restAPI-IP' + ':' + '8080'
, protocol: 'http'
, pathname: 'your-rest-endpt/'
};
console.log('options: ');
console.dir(options);
var reqUrl = url.format(options);
console.log("Forward URL: "+reqUrl);
var parsedUrl = url.parse(req.url, true);
console.log('parsedUrl: ');
console.dir(parsedUrl);
var queryParams = parsedUrl.query;
var path = parsedUrl.path;
var substr = path.substring(path.lastIndexOf("rest/"));
console.log('substr: ');
console.dir(substr);
reqUrl += substr;
console.log("Final Forward URL: "+reqUrl);
var newHeaders = {
};
//Deep-copy it, clone it, but not point to me in shallow way...
for (var headerKey in req.headers) {
newHeaders[headerKey] = req.headers[headerKey];
};
var newBody = (req.body == null || req.body == undefined ? {} : req.body);
if (newHeaders['Content-type'] == null
|| newHeaders['Content-type'] == undefined) {
newHeaders['Content-type'] = 'application/json';
newBody = JSON.stringify(newBody);
}
var requestOptions = {
headers: {
'Content-type': 'application/json'
}
,body: newBody
,method: 'POST'
};
console.log("server.js : routes to URL : "+ reqUrl);
request(reqUrl, requestOptions, function(error, response, body){
if(error) {
console.log('The error from Tomcat is --> ' + error.toString());
console.dir(error);
//return false;
}
if (response.statusCode != null
&& response.statusCode != undefined
&& response.headers != null
&& response.headers != undefined) {
res.writeHead(response.statusCode, response.headers);
} else {
//404 Not Found
res.writeHead(404);
}
if (body != null
&& body != undefined) {
res.write(body);
}
res.end();
});
});
#Swapnil Niwane
I was able to solve this issue by calling an ajax request and formatting the data to 'jsonp'.
$.ajax({
method: 'GET',
url: url,
defaultHeaders: {
'Content-Type': 'application/json',
"Access-Control-Allow-Origin": "*",
'Accept': 'application/json'
},
dataType: 'jsonp',
success: function (response) {
console.log("success ");
console.log(response);
},
error: function (xhr) {
console.log("error ");
console.log(xhr);
}
});
I have found a way to use JSONP method in $http directly and with support of params in the config object:
params = {
'a': b,
'callback': 'JSON_CALLBACK'
};
$http({
url: url,
method: 'JSONP',
params: params
})
Try with this:
$.ajax({
type: 'POST',
url: URL,
defaultHeaders: {
'Content-Type': 'application/json',
"Access-Control-Allow-Origin": "*",
'Accept': 'application/json'
},
data: obj,
dataType: 'json',
success: function (response) {
// BindTableData();
console.log("success ");
alert(response);
},
error: function (xhr) {
console.log("error ");
console.log(xhr);
}
});

Categories

Resources