Cross-Origin Request Blocked Angular JS Put request - javascript

I'm developing a REST-ful application using Yii framework for the server side and Angular JS for the client side
I'm using the restfulyii extension to generate the api
:And I'm facing a problem when I'm sending a PUT request.
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at ..... This can be fixed by moving the resource to the same domain or enabling CORS.
But it's working for post + get requests
I saw different solutions but none of them worked.
I tried to put those is server side
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS");
header("Access-Control-Allow-Headers: x-requested-with, Content-Type, origin, authorization, accept, client-security-token");
header("Access-Control-Max-Age: 1000");
and tried to put this code in the angular js module:
$httpProvider.defaults.useXDomain = true;
delete $httpProvider.defaults.headers.common['X-Requested-With'];
and also I tried to put
$http.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded";
The request converted into OPTIONS request
and the response from the server became as following:
Access-Control-Allow-Headers:x-requested-with, Content-Type, origin, authorization, accept, client-security-token
Access-Control-Allow-Methods:GET, POST, PUT, DELETE, OPTIONS Access-Control-Allow-
Origin:http://localhost:8383
Access-Control-Max-Age:1000
Connection:close
Content-Type:text/html Date:Fri, 24 Oct 2014 06:49:32 GMT
Server:Apache/2.4.7 (Win32) OpenSSL/1.0.1e PHP/5.5.9 X-Powered-By:PHP/5.5.9

I have a base controller for all my rest controllers that use restangular which has the following events.
public function restEvents()
{
$this->onRest('req.cors.access.control.allow.origin', function() {
return ['*']; //List of sites allowed to make CORS requests
});
$this->onRest('req.cors.access.control.allow.methods', function() {
return ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS']; //List of allowed http methods (verbs)
});
$this->onRest('req.auth.cors', function ($allowed_origins) {
if (in_array('*', $allowed_origins)) {
return true;
}
if((isset($_SERVER['HTTP_ORIGIN'])) && (( array_search($_SERVER['HTTP_ORIGIN'], $allowed_origins)) !== false )) {
return true;
}
return false;
});
$this->onRest('req.cors.access.control.allow.headers', function($application_id) {
return ["X_{$application_id}_CORS", "Content-Type", "Authorization", "X_REST_REQUEST"];
});
}
Client side I am using restangular with the following options:
RestangularProvider.setDefaultHttpFields({withCredentials: true});
RestangularProvider.setDefaultHeaders({X_REST_CORS: 'Yes'});
RestangularProvider.setDefaultHttpFields({cache: false});
I hope this helps....

Related

CORS/JavaScript/Laravel: Sending request to Digital Ocean server and receiving data (Headers issues)

So, what I'm trying to do is use a Digital Ocean droplet as an api for an application hosted on a different server. Currently, I'm just developing so this server is from my localhost:3000.
On my client side code (JavaScript) I have:
handleSendData = () => {
const request = new XMLHttpRequest()
request.open('POST', 'http://my-droplet-ip/api/create-image')
request.setRequestHeader('Content-Type', 'application/json; charset=UTF-8')
request.setRequestHeader('Access-Control-Allow-Origin', 'http://my-droplet-ip')
request.send(JSON.stringify(data-object))
}
Finally, in my Laravel application (Laravel Framework 5.8.18) I have a route under routes/api.php:
Route::post('/create-image', 'CreateData');
And I have a controller CreateData.php:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class CreateImage extends Controller
{
/**
* Handle the incoming request.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function __invoke(Request $request)
{
return response('Hello World', 200)
->header('Content-Type', 'application/json; charset=UTF-8')
->header('Access-Control-Allow-Origin', '*');
}
}
The problem is when I try to run this request, I get a CORS error:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://my-droplet-ip/api/create-image. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing)
Under the networking tab I get a 404 not found and the Access header is not there in the response.
Any thoughts out there on this issue?
There is a simple solution to this and it is ok for testing on you local machine.
You could just put in index file to allow cors, but I suggest you building middleware for this.
Here is a link it is explained really nice:)
https://medium.com/#petehouston/allow-cors-in-laravel-2b574c51d0c1
You can put also this in index.php
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST, PATCH, PUT, DELETE, OPTIONS');
header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
Hope it helps :D

angular 4 not send cookie to server

When I use withCredentials I can see that cookies are sent to the server. But are send anything to the server. I use laravel as backend and angular 4 as frontend.
also, the cookie not shown on chrome developer tools and I can't access them using.
also, I used Cors middleware in laravel like:
<?php
namespace App\Http\Middleware;
use Closure;
class Cors
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
$response = $next($request);
$response->headers->set('Access-Control-Allow-Origin', 'http://localhost:4200');
$response->headers->set('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
$response->headers->set('Access-Control-Allow-Headers', 'Content-Type, Accept, Authorization, X-Request-With');
$response->headers->set('Access-Control-Expose-Headers', 'Content-Disposition, x-total-count, x-filename');
$response->headers->set('Access-Control-Allow-Credentials', 'true');
return $response;
}
}
and when I request first time to the server for set cookie, these below response show:
Access-Control-Allow-Credentials:true
Access-Control-Allow-Headers:Content-Type, Accept, Authorization, X-Request-With
Access-Control-Allow-Methods:GET, POST, OPTIONS, PUT, PATCH, DELETE
Access-Control-Allow-Origin:http://localhost:4200
Access-Control-Expose-Headers:Content-Disposition, x-total-count, x-filename
Cache-Control:no-cache, private
Connection:keep-alive
Content-Type:application/json
Date:Tue, 02 Jan 2018 09:04:32 GMT
Server:nginx/1.11.9
Set-Cookie:refreshToken=def502005a2ccf60eafdee2137df25a628d49f70c4571bedde628d50e45c0fe4b73f84f86bb469f0f77247dc2abc13c0c5c938027beb13fe534eb7bb41f4aed99faf49ebf2a238a007ce9514108951366db45a311d70d17d65dd48f5df6aa50f257c828cce16e589983c1e06c9e8d7d52806a1a9401569f87b3a394469e938c4ddbfcc7985e257d8f0d0df416e7b8a5bbd19e86050db3be5b90953c515934f529489f4e0ba62fb66ab883d1689349bbfb962332bceb322d978b7d20fa7e32bb94eb0050d8f94bfd3a780c4edfeea8eaa6954222b57c30229c2494fec38ee5292396400b25fadee04cad1729f9e9b9ccf12d21a6ed3f9663d41c5423536e64f83542df19fcede28247bfc12accf354e035182c3e019e4a2b55c807924cc50a12fa187b2f655fb19c1b42a1ae526763dd08dbd0d288b3a9c649216ab1abc60cd51bb97dfb0cb7b7b020ff270cf5c81bc94f2acd40f92edeefaf585d46d0750bf; expires=Sun, 25-Aug-2019 09:04:32 GMT; Max-Age=51840000; path=/; HttpOnly
Transfer-Encoding:chunked
X-RateLimit-Limit:60
X-RateLimit-Remaining:58
and when I request from frontend:
refreshToken(){
const headers = new Headers({ 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + this.getToken()})
let options = new RequestOptions({ headers: headers, withCredentials: true });
return this.http.post(API_DOMAIN + 'refresh', JSON.stringify({}), options)
.map(
(response) => {
console.log(response);
return response.json()
},
)
.do(
tokenData =>{
localStorage.setItem('token', tokenData.access_token)
localStorage.setItem('expires_in', tokenData.expires_in)
}
)
}
chrome develope:
Access-Control-Allow-Credentials:true
Access-Control-Allow-Headers:Content-Type, Accept, Authorization, X-Request-With
Access-Control-Allow-Methods:GET, POST, OPTIONS, PUT, PATCH, DELETE
Access-Control-Allow-Origin:http://localhost:4200
Access-Control-Expose-Headers:Content-Disposition, x-total-count, x-filename
Cache-Control:no-cache, private
Connection:keep-alive
Content-Type:application/json
Date:Tue, 02 Jan 2018 08:57:28 GMT
Server:nginx/1.11.9
Transfer-Encoding:chunked
X-RateLimit-Limit:60
X-RateLimit-Remaining:59
Front and back servers use different ports.
You can's save cookies because your development node.js server and your Laravel Vagrant box are on different domains. What you can do is to proxy calls from node.js to the the Laravel server.
Create proxy.conf.json in the root of Angular app. Put an object with routes inside:
{
"/api": {
"target": "http://mydomian.test/",
"secure": false
}
}
I just have /api defined here because all my backend URIs are inside api.php. All calls that look like http://localhost:4200/api/someitems/1 will be proxied to http://mydomian.test/api/someitems/1.
Then edit package.json and change the value of start inside scripts to ng serve --proxy-config proxy.conf.json. Now npm run start will start with proxy. The problem I had with this proxy is that it resolves your URL (http://mydomian.test/) to an IP. When it calls Laravel with just an IP the nginx server does not know what to do because it must receive a domain name. nginx allows multiple website on the same IP so it must receive a domain name or to have a default website to which it redirects all calls those have no domain name. In case this is still not fixed in Angular's proxy go to /etc/nginx/sites-available on the Laravel machine, you'll have a mydomian.test config file there. It has listen 80; line there, change it to listen 80 default;.
Now you can change the API_DOMAIN variable to http://localhost:4200 (or remove it all together) and disable the CORS.

HTTP 405 error while trying to DELETE from web service

I have a simple Java web service that handles my SQL method with Jersey. The HTTP call is from an Angular project. GET and POST are working fine, but when I try a DELETE, I get an HTTP 405 error.
This is how I call the method in Angular:
deletaDados(id){
this.service.deleteData(id)
}
+
deleteData(id){
return this.http.delete(`${this.api}/${id}`).subscribe((res) => {
});;
}
And this is the DELETE Java method:
#DELETE
#Path("{id}/")
public Response delete(#PathParam("id") long id) throws SQLException, ClassNotFoundException{
ofertaDAO dao = new ofertaDAO();
dao.delete(id);
return Response
.status(200)
.header("Access-Control-Allow-Origin", "*")
.header("Access-Control-Allow-Headers", "origin, content-type, accept, authorization")
.header("Access-Control-Allow-Credentials", "true")
.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, HEAD")
.header("Access-Control-Max-Age", "1209600")
.entity(id)
.build();
}
Seem right... No idea why I'm getting the 405 error.
If the DELETE coming from your frontend JavaScript code is a cross-origin request, then your browser (automatically on its own) will send a CORS preflight OPTIONS request first.
So it seems like the 405 you’re seeing may be the response to that preflight OPTIONS request — and if so, then you’ll need to have an explicit OPTIONS handler in your server-side Java code.
That OPTIONS handler should just send back a response with a 200 status and the necessary CORS headers, with no response body; so, something like this:
#OPTIONS
public Response options(){
return Response
.status(200)
.header("Access-Control-Allow-Origin", "*")
.header("Access-Control-Allow-Headers", "origin, content-type, accept, authorization")
.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, HEAD")
.header("Access-Control-Max-Age", "1209600")
.build();
}
Incidentally, also note that for the Access-Control-Max-Age response header there’s probably not much point in setting a value that’s any greater than 600 (10 minutes) — because if you do set a value greater than that for it, Chrome will just clamp it to 600 anyway.
And as far as why you don’t also run into that 405 when you send a GET or POST from your frontend JavaScript code, the reason is that the GET and POST requests your code is sending don’t have characteristics (such as custom headers) that’ll trigger your browser to do a preflight. But cross-origin DELETE requests always trigger browsers to do a preflight.

Error HTTP GET object list

I get an error when I try to retrieve a list of objects from a link (php server).
Blocking of a multi-origin request (cross-origin request): the "same
source" policy does not allow access to the remote resource located at
http: //localhost/eReport/index.php. Reason:
"Access-control-authorization-origin" token missing in the CORS
"Access-Control-Allow-Headers" CORS header.
I added a header like this tuto that is recommended on this link but I still have this error.
Can you help me please ?
My Service page:
#Injectable()
export class ReportService{
private baseUrl: string = 'http://localhost/report/reports.php';
constructor(private http : Http){}
getAll(): Observable<Report[]>{
let report$ = this.http
.get(`${this.baseUrl}`, { headers: this.getHeaders()})
.map(mapReports);
return report$;
}
private getHeaders(){
// I included these headers because otherwise FireFox
// will request text/html
let headers = new Headers();
headers.append('Accept', 'application/json');
headers.append('Content-Type', 'application/x-www-form-urlencoded;charset=UTF-8');
return headers;
}
get(id: number): Observable<Report> {
let report$ = this.http
.get(`${this.baseUrl}/report/${id}`, {headers: this.getHeaders()})
.map(mapReport);
return report$;
}
My php page
header("Access-Control-Allow-Origin: *");
$tab = array(
array('id'=> '12', 'name'=> 'test','description' => '2018-04-01','url'=>'../../../assets/img/chat1.png' ),
array('id'=> '13', 'name'=> 'test','description' => '2018-04-01','url'=>'../../../assets/img/highcharts.png' )
);
echo json_encode($tab);
?>
Perhaps the quickest fix is to change your base url in the Angular app to /report/reports.php if the requests are going to the same server that served the app.
Your request is not working because when the client sends content of type application/json, the browser doesn't send the request right away. If you restart your browser then observe the network tab you will notice that instead of your GET, an OPTIONS request is first send, that includes headers similar to these:
Origin: yourserver
Access-Control-Request-Method: GET
Access-Control-Request-Headers: Content-Type, Accept
In this scenario, the browser expects the server to return not just the Access-Control-Allow-Origin header (which you're already doing), but all of these:
Access-Control-Allow-Origin: yourserver (or *)
Access-Control-Allow-Methods: GET (or a list eg: GET, POST, OPTIONS)
Access-Control-Allow-Headers: Content-Type, Accept (the same headers from above)
So you need to read the request headers from the previous block, and use their values when setting the response headers. If you have the apache_request_headers() method it's pretty easy. You can also get them from the $_SERVER superglobal.
// set required headers:
header("Access-Control-Allow-Origin: $_SERVER[HTTP_ORIGIN]");
header("Access-Control-Allow-Methods: $_SERVER[HTTP_ACCESS_CONTROL_REQUEST_METHOD]");
header("Access-Control-Allow-Headers: $_SERVER[HTTP_ACCESS_CONTROL_REQUEST_HEADERS]");
See this helpful article

AngularJS: POST Data to External REST API

I have a basic AngularJS service setup like so:
app.factory('User', function($resource) {
return $resource('http://api.mysite.com/user/:action:id/:attr', {}, {
history: {
method: 'GET',
params: {
attr: 'history'
}
},
update: {
method: 'POST',
params: {
name: 'test'
}
}
});
});
and I use it like this:
User.history({id: 'testID'}, function(data) {
console.log('got history');
console.log(data);
});
User.update({id: 'me'}, function(data) {
console.log('updated');
console.log(data);
});
Problem one: User.update(), despite having the method set to POST, keeps sending OPTIONS as the request method.
Though Chrome Dev tools reports the request header Access-Control-Request-Method:POST is sent as well (Not sure if that means anything).
Problem two: I keep getting an error with CORS, despite having these headers set in the API code:
header('Access-Control-Allow-Origin: *');
header("Access-Control-Allow-Methods: PUT, GET, POST, DELETE, OPTIONS");
This problem only shows up though if making a non-GET request.
What's the proper way to be handling this? I've also looked into JSONP, but with this being a RESTful api, I'm not sure how to get around the problems with only GET support.
Your two problems are actually one problem. The OPTIONS request is part of the CORS process. For POST requests, the browser first sends an OPTIONS call, and the server responds if it is okay to execute it.
If the OPTIONS request fails, Angular / Chrome shows you the reason in the console. For example:
OPTIONS https://*** Request header field Content-Type is not allowed by Access-Control-Allow-Headers. angular.min.js:106
XMLHttpRequest cannot load https://***. Request header field Content-Type is not allowed by Access-Control-Allow-Headers.
You probably have to set Access-Control-Allow Headers on the server, too:
header('Access-Control-Allow-Headers: Content-Type, x-xsrf-token')
x-xrsf-token is for angular' to prevent CSRF. You may have to add more headers, depending on what you send from the client.
Here is a very good guide on CORS: https://developer.mozilla.org/en-US/docs/HTTP/Access_control_CORS
In AngularJS to make CORS working you also have to overwrite default settings of the angular httpProvider:
var myApp = angular.module('myApp', [
'myAppApiService']);
myApp.config(['$httpProvider', function($httpProvider) {
$httpProvider.defaults.useXDomain = true;
delete $httpProvider.defaults.headers.common['X-Requested-With'];
}
]);
Just setting useXDomain to true is not enough. AJAX request are also
send with the X-Requested-With header, which indicate them as being
AJAX. Removing the header is necessary, so the server is not rejecting
the incoming request.
Note: Answer only works for older AngularJS version previous to 1.2. With 1.2 and above you don't have to do do anything to enable CORS.
Better to solve this problem at the server. On apache you can solve it like this in a .htaccess file. This is a source of pain for angular development and can be solved in angular as well but its probably not the best way to do it.
Header set Access-Control-Allow-Origin "*"
Header add Access-Control-Allow-Headers "origin, x-requested-with, content-type"
Header add Access-Control-Allow-Methods "PUT, GET, POST, DELETE, OPTIONS"

Categories