I am new to angular2. I am trying to login to my Django server which is a production server from localhost where i am currently writing my front end code. Also, I am port forwarding to my production server. I keep getting the CORS issue. Here is the error i get in my console:
XMLHttpRequest cannot load https://www.smartkart.ca/api/user/login/. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
I have written my HTTpService and have read almost all the blogs out there to figure out an solution but no luck. I believe i need to use the withCredentials: true property. I read some blogs and have modified my code to support withCredentials but no luck.
Here is my code snippet:
import {Injectable} from 'angular2/core';
import {Http} from 'angular2/http';
import 'rxjs/add/operator/map';
import {Headers} from 'angular2/http';
import {BaseRequestOptions, RequestOptions} from 'angular2/http';
@Injectable()
export class HTTPService {
constructor(private _http: Http) {
}
baseUrl: String = "https://www.smartkart.ca/";
getStoreList() {
return this._http.get(this.baseUrl + 'api/current/store/')
.map(res => res.json());
};
getCookie(name) {
let value = "; " + document.cookie;
let parts = value.split("; " + name + "=");
if (parts.length == 2)
return parts.pop().split(";").shift();
};
login(){
// var request = new XMLHttpRequest();
// var params = JSON.stringify({'email': '[email protected]', 'password': 'k0ttawa#1234'});
// request.open('POST', this.baseUrl+ "api/user/login/", true);
// request.onreadystatechange = function() {if (request.readyState==4) alert("It worked!");};
// request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
// request.setRequestHeader("Content-length", params.length.toString());
// request.setRequestHeader("Connection", "close");
// request.send(params);
var data = JSON.stringify({'email': '[email protected]', 'password': 'blahblah'});
var params = data;
var headers = new Headers ();
headers.append('Accept', 'application/json');
headers.append('Authorization', 'Basic ' + btoa('[email protected]:k0ttawa#1234'));
headers.append("Content-type", "application/x-www-form-urlencoded, application/json");
// headers.append("Content-length", params.length.toString());
// headers.append('Access-Control-Allow-Origin', '*');
// headers.append('Access-Control-Request-Headers', 'x-requested-with');
// headers.append('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
// headers.append('Access-Control-Allow-Headers', 'X-Requested-With,content-type');
// headers.append('Access-Control-Allow-Credentials', 'true');
// headers.append('Content-Type', 'pplication/x-www-form-urlencoded');
// headers.append('X-CSRFToken', this.getCookie('csrftoken'));
return this._http.post(this.baseUrl+ "api/user/login/", params,
{
headers: headers
}
).map(res => res.json())
};
}
here is what i see in my network tab in the browser
Now if i take away the authorization header i do get logged in and i get back the csrf token but i can never get any response from the server due to the CORS issue. Here is a snapshot
I read some blogs where there were workarounds. I tried that too but no success.
Here is my code for the workaround:
import {Injectable} from 'angular2/core';
import {BrowserXhr } from 'angular2/http';
@Injectable()
export class CORSBrowserXHr extends BrowserXhr {
build(): any {
let xhr = super.build();
xhr.withCredentials = true;
return <any>(xhr);
}
}
And in bootstrap i add the following:
/// <reference path="../typings/browser.d.ts" />
import {bootstrap} from 'angular2/platform/browser';
import {AppComponent} from "./app.component";
import {ROUTER_PROVIDERS} from "angular2/router";
import {APP_BASE_HREF} from 'angular2/router';
import {provide} from 'angular2/core';
import {LocationStrategy, HashLocationStrategy} from 'angular2/router';
import {HTTP_PROVIDERS} from "angular2/http";
import {BrowserXhr} from 'angular2/http';
import {CORSBrowserXHr} from "./CORSBrowserXHr.services";
bootstrap(AppComponent, [ROUTER_PROVIDERS, HTTP_PROVIDERS, provide(BrowserXhr, {useClass:CORSBrowserXHr}),
provide(LocationStrategy, {useClass: HashLocationStrategy})]);
I understand angular2 is under beta but i believe that by now they must have comeup with a solution for CORS support. If someone has any ideas please comment.
Thanks in advance!!
In fact, there are two main cases in CORS:
Simple requests. We are in this case if we use HTTP methods GET
, HEAD
and POST
. In the case of POST
method, only content types with following values are supported: text/plain
, application/x-www-form-urlencoded
, multipart/form-data
. Even if you're in these case and if you use a custom header (a header that you define by your own in your request), you'll fall into the preflighted request.
Preflighted requests. When you aren't in the case of simple requests, a first request (with HTTP method OPTIONS
) is done to check what can be done in the context of cross-domain requests.
In your case, you're in the second case (preflighted request) since you use a custom header (defined by your own), the Authorization
one.
But the corresponding OPTIONS request doesn't define a Access-Control-Allow-Origin
header in its response. This would allow the browser to determine if you're (localhost:3000 for example) able to execute the target request.
In fact, it's not a problem in your Angular2 application but in the server application you try to access. The latter should return the appropriate CORS headers like the Access-Control-Allow-Origin
one. Otherwise your browser will block the request...
These articles could interest you: