I am developing an angularjs app which uses laravel as its back end server.
I am having trouble accessing data from laravel since before each GET request, angular first sends an OPTION request as below.
OPTIONS /61028/index.php/api/categories HTTP/1.1
Host: localhost
Connection: keep-alive
Cache-Control: max-age=0
Access-Control-Request-Method: GET
Origin: http://localhost:3501
Access-Control-Request-Headers: origin, x-requested-with, accept
Accept: */*
Referer: http://localhost:3501/
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Accept-Charset: UTF-8,*;q=0.5
I have tried to respond this by adding the following code in the before filter
if (Request::getMethod() == "OPTIONS") {
$headers = array(
'Access-Control-Allow-Origin' => '*',
'Access-Control-Allow-Methods' => 'POST, GET, OPTIONS, PUT, DELETE',
'Access-Control-Allow-Headers' => 'X-Requested-With, content-type'
);
return Response::make('', 200, $headers);
}
This creates a response with the headers:
Content-Encoding: gzip
X-Powered-By: PHP/5.3.5-1ubuntu7.11
Connection: Keep-Alive
Content-Length: 20
Keep-Alive: timeout=15, max=97
Server: Apache/2.2.17 (Ubuntu)
Vary: Accept-Encoding
access-control-allow-methods: POST, GET, OPTIONS, PUT, DELETE
Content-Type: text/html; charset=UTF-8
access-control-allow-origin: *
cache-control: no-cache
access-control-allow-headers: X-Requested-With, content-type
Although the headers are set, the browser still throws an error
XMLHttpRequest cannot load http://localhost/61028/index.php/api/categories. Origin http://localhost:3501 is not allowed by Access-Control-Allow-Origin.
I have also tried setting the allow origin to the origin presented in the request header as below
$origin=Request::header('origin');
//then within the headers
'Access-Control-Allow-Origin' =>' '.$origin[0],
and still the same error
What am i doing wrong? Any help is greatly appreciated.
Edit 1
I am currently using a very ugly hack where i over-ride laravels initialization when an OPTIONS request is received. This i have done in the index.php
<?php
if ($_SERVER['REQUEST_METHOD']=='OPTIONS') {
header('Access-Control-Allow-Origin : *');
header('Access-Control-Allow-Methods : POST, GET, OPTIONS, PUT, DELETE');
header('Access-Control-Allow-Headers : X-Requested-With, content-type');
}else{
/**
* Laravel - A PHP Framework For Web Artisans
*
* #package Laravel
* #version 3.2.13
* #author Taylor Otwell <taylorotwell#gmail.com>
* #link http://laravel.com
*/
I also had to add the allow-origin header to the before filter.
I know this is not smart but it is my only solution for now
This is with reference to your question regarding the above issue. You did not mention the version of laravel and angularJS. I assume you are using lattest angularJS and Laravel. I also assume, the angular is hosted on http://localhost:3501 and the laravel is hosted on http://localhost
Just follow the below steps.
Put below code block in /public/.htaccess file of laravel
Header set Access-Control-Allow-Origin "http://localhost:3501"
Header set Access-Control-Allow-Methods "GET,POST,PUT,DELETE,OPTIONS"
Header set Access-Control-Allow-Credentials "true"
Put below line in config of angular
$httpProvider.defaults.withCredentials = true;
Never use * as wild card character. Larvel can not identify the domain for session management. So set http://localhost:3501 as full domain name to Access-Control-Allow-Origin.
I think these will help you.
It's a bug in Laravel that got recently fixed. You may want to update to the latest revision.
Also, you need to enable CORS support for your server.
add this in your index.php file
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST, PATCH, PUT, DELETE, OPTIONS');
header('Access-Control-Allow-Headers: Origin, Content-Type, X-Auth-Token');
Related
Im using Ionic as my apps development and laravel as the server. I recently moved my laravel project from localhost to production VPS Server. At localhost, my API requests are fine. But when i moved the project to VPS Server, the request firing twice at one time.
What i've done =
Re-Upload the project from localhost to vps server (including database)
Re-Upload the project using git.
Cleared route, view, cache, config (laravel cache)
But nothing change, the problem still occur.
{\"data\":[{\"id\":53,\"name\":\"Rumah\",\"user_id\":2,\"receipent\":\"John Doe\",\"receipent_phone\":\"62812345678\",\"address\":\"Los Angeles\",\"district\":\"Bengkong, Batam, Kepulauan Riau\",\"district_id\":5}]}"}}
[2020-07-10 20:59:01] local.INFO: app.requests {"request":[],"method":"DELETE","response":{"Illuminate\\Http\\JsonResponse":"HTTP/1.1 200 OK
Access-Control-Allow-Headers: X-Requested-With, Content-Type, X-Token-Auth, Authorization
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Origin: *
Cache-Control: no-cache, private
Content-Type: application/json
Date: Fri, 10 Jul 2020 13:59:01 GMT
X-Ratelimit-Limit: 120
X-Ratelimit-Remaining: 115
{\"message\":\"Sukses menghapus data\"}"}}
[2020-07-10 20:59:01] local.INFO: app.requests {"request":[],"method":"DELETE","response":{"Illuminate\\Http\\JsonResponse":"HTTP/1.1 404 Not Found
Access-Control-Allow-Headers: X-Requested-With, Content-Type, X-Token-Auth, Authorization
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Origin: *
Cache-Control: no-cache, private
Content-Type: application/json
Date: Fri, 10 Jul 2020 13:59:01 GMT
X-Ratelimit-Limit: 120
X-Ratelimit-Remaining: 114
{\"message\":\"No data\"}"}}
Above are the Logging details from my laravel project about the API incoming request on VPS server. You can see the request Time are the same. But, when im using Postman, the request is normal, like when i'm using localhost I'm new to this. any help would be appreciated, Thank you.
Update 2 (A complete set of logs)
From Client's Perspective
Request headers:
POST /dev/micro_server.php HTTP/1.1
Host: production-server.com
Connection: keep-alive
Content-Length: 86
Pragma: no-cache
Cache-Control: no-cache
Accept: text/html, /; q=0.01
Origin: https://debug.dev
User-Agent: Mozilla/5.0 (X11; Linux x86_64)
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98
Safari/537.36 OPR/58.0.3135.90
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Referer: https://debug.dev/
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Cookie: debugger_session=iq4tbdk374mtvodsd3edcf2jq5
Response headers:
HTTP/1.1 200 OK
Server: nginx/1.4.6 (Ubuntu)
Date: Tue, 12 Mar 2019 12:01:27 GMT
Content-Type: text/html
Transfer-Encoding: chunked
Connection: keep-alive
X-Powered-By: PHP/5.5.9-1ubuntu4.17
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Origin: https://production-server.com
Access-Control-Allow-Credentials: true
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Content-Encoding: gzip
Console Error:
Access to XMLHttpRequest at 'https://production-server.com/dev/micro_server.php' from origin 'https://debug.dev' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header has a value 'https://production-server.com' that is not equal to the supplied origin.
Console Warning:
Cross-Origin Read Blocking (CORB) blocked cross-origin response https://daikai.no/dev/micro_server.php with MIME type text/html. See https://www.chromestatus.com/feature/5629709824032768 for more details.
From Server's Perspective
This is what the server says it has received and sent (check the code that does the logging in update 1):
Array
(
[req] => Array
(
...
[HTTP_ORIGIN] => https://debug.dev
...
)
[rsp] => Array
(
[0] => X-Powered-By: PHP/5.5.9-1ubuntu4.17
[1] => Access-Control-Allow-Origin: https://debug.dev
[2] => Access-Control-Allow-Methods: GET, POST, OPTIONS
[3] => Access-Control-Allow-Credentials: true
)
)
Update
I have added some logging on the server and the script now begins with these lines:
# allow access from other domains
header("Access-Control-Allow-Origin: " . $_SERVER['HTTP_ORIGIN']);
header("Access-Control-Allow-Methods: GET, POST, OPTIONS");
header("Access-Control-Allow-Credentials: true");
$all = [
'req' => $_SERVER,
'rsp' => headers_list()
];
$s = print_r($all, true);
$p = '/var/www/path/to/file_' . uniqid() . '.txt';
file_put_contents($p, $s);
With this I can confirm that the request arrives on the server with the correct Origin, AND the server sends back the correct CORS headers. Yet, the Access-Control-Allow-Origin in the developer console is wrong and the request is blocked.
Here is a stripped down log obtained with the code above:
Array
(
[req] => Array
(
...
[HTTP_ORIGIN] => https://debug.dev
...
)
[rsp] => Array
(
[0] => X-Powered-By: PHP/5.5.9-1ubuntu4.17
[1] => Access-Control-Allow-Origin: https://debug.dev
[2] => Access-Control-Allow-Methods: GET, POST, OPTIONS
[3] => Access-Control-Allow-Credentials: true
)
)
Question
How and why does the Access-Control-Allow-Origin is changed to https://production.com when the actual header received is Access-Control-Allow-Origin: https://debug.dev?
(Original Post)
Background
I have a web-based debug tool that I have installed on my local development machine. With an entry in my /etc/hosts I have assigned to it the domain debug.dev. I have also added a local CA authority and have successfully created a SSL certificate for the domain name so now I can open https://debug.dev/ in my browser and the debug tool opens normally.
This tool is supposed to work with staging and production servers. So it needs to send AJAX requests to other domains. I have full control over those servers and I am sending back CORS headers from those servers like so:
header("Access-Control-Allow-Origin: " . $_SERVER['HTTP_ORIGIN']);
header("Access-Control-Allow-Credentials: true");
The Issue
Now I am facing a baffling situation in which when I send an AJAX request to the production server I get back Wrong CORS headers with the SERVER's domain like this:
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: https://production-server.com
But if I right click and use Open in new tab the CORS headers are what they ought to be; i.e.
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: https://debug.dev
The only differences between the requests as far as I can see is that the first one is sent as an AJAX POST request and thus sends a HTTP_X_REQUESTED_WITH header whereas the second request is sent as an ordinary GET request. How could this result in a different CORS header be returned by the server?
The issue could be similar as my answer here:
The server is not configured to respond to OPTIONS requests with the correct "Access-Control-Allow-" headers.
Opening the url in a new Tab is a GET request and is working because it is not making a preflight request, as it meets the criteria to be a simple request as defined by the CORS documentation
On the other hand, the ajax request is a POST request and meets the criteria to be a Preflighted request, meaning a preflight OPTIONS request should be made first.
In short, you have correctly setup the CORS response headers, but the server is not configured to add these headers for OPTIONS method requests.
The solution is to handle OPTIONS requests on the server code with a 2xx response and add the **Access-Control-Allow- as you do for GET and POST requests. Keep in mind that OPTIONS requests do not include any parameters, so this should be done before any validation or request parsing.
Moreover, according to Access-Control-Allow-Origin documentation:
If the server specifies a single origin rather than the "*" wildcard, then the server should also include Origin in the Vary response header — to indicate to clients that server responses will differ based on the value of the Origin request header.
So set the Vary response header also:
eg at the top of you script try:
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
header("Access-Control-Allow-Origin: " . $_SERVER['HTTP_ORIGIN']);
header("Access-Control-Allow-Methods: GET, POST, OPTIONS");
header("Access-Control-Allow-Credentials: true");
header("Vary: Origin");
exit;
}
References
Preflighted requests
response for preflight 403 forbidden
The problem is that you use header("Access-Control-Allow-Origin: " . $_SERVER['HTTP_ORIGIN']); (BTW: not very recommended) and you get the wrong header. I bet on one of the reasons:
The web server overwrites the headers.
The browser uses cache, although it should not. (BFC).
You did not upload the updated code to the requesting server.
Let's start from the end.
Do not believe herself, verify. (Not once did I look, we do not work, and then came the reflection that I did not upload changes :) ).
Turn off the cache in the browser debugger. (you must have open debugger) If this is a problem and the function is to be available in the pool, add timestamp to the request.
Check the configuration of nginx / apache / server panel
Are you aware that the construction used by you is synonymous with Access-Control-Allow-Origin: *? You should check HTTP_ORIGIN if it belongs to the allowed pool.
Im trying to implement an API based on PHP and Slim, but keep getting CORS error “No 'Access-Control-Allow-Origin' header is present on the requested resource” error . But clearly I have it set.
I have searched all over the internet to enable CORS in my api.
Url for testing: http://www.ricardochen.com/index2.php
I have even stripped everything down to just this (php):
<?php
$data = "test";
header('Content-Type: application/json');
echo json_encode($data);
?>
.htaccess
Header always set Access-Control-Allow-Origin "*"
Header always set Access-Control-Max-Age "1000"
Header always set Access-Control-Allow-Headers "X-Requested-With, Content-Type, Origin, Authorization, Accept, Client-Security-Token, Accept-Encoding"
Header always set Access-Control-Allow-Methods "POST, GET, OPTIONS, DELETE, PUT"
RewriteEngine On
# Some hosts may require you to use the `RewriteBase` directive.
# If you need to use the `RewriteBase` directive, it should be the
# absolute physical path to the directory that contains this htaccess file.
#
# RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [QSA,L]
My header according to chrome inspector
GENERAL:
Request URL:http://ricardochen.com/index2.php
Request Method:GET
Status Code:200 OK
Remote Address:198.46.81.208:80
Referrer Policy:no-referrer-when-downgrade
Response Headers
Access-Control-Allow-Headers:X-Requested-With, Content-Type, Origin, Authorization, Accept, Client-Security-Token, Accept-Encoding
Access-Control-Allow-Methods:POST, GET, OPTIONS, DELETE, PUT
Access-Control-Allow-Origin:*
Access-Control-Max-Age:1000
Connection:Upgrade, Keep-Alive
Content-Type:application/json
Date:Fri, 19 Jan 2018 23:08:32 GMT
Keep-Alive:timeout=3, max=100
Server:Apache
Transfer-Encoding:chunked
Upgrade:h2,h2c
X-Powered-By:PHP/5.4.45
Request Headers
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding:gzip, deflate
Accept-Language:en
Cache-Control:no-cache
Connection:keep-alive
Cookie:_ga=GA1.2.637285574.1502508699
Host:ricardochen.com
Pragma:no-cache
Upgrade-Insecure-Requests:1
User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36
I have tried setting the header in php, in .htaccess, in both, tried in 2 different shared hostings, tried on my localhost and same behaviour.
Please help
When cross origin request is performed, a browser sends OPTIONS request beforehand to find out what is allowed and expects to get headers in response like following:
Access-Control-Allow-Headers: Authorization
Access-Control-Allow-Method: OPTIONS, GET, POST, DELETE, PUT
Access-Control-Allow-Origin: *
Allow: OPTIONS, GET, POST, DELETE, PUT
After a browser sees these headers, it knows it is allowed to make GET request. Ensure your reply to OPTIONS correctly.
At the end did not know what happened, probably my testing methods was the issue.
It is working.
Thanks.
I have a chorme plugin that allows me to toggle CORS by inserting a header. If I use that my slim code works. If not then I get an error as follows.
(index):1 XMLHttpRequest cannot load
http://localhost/api/flowers. No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'http://localhost:9000' is therefore not allowed
access.
My code
$app = new \Slim\Slim();
$app->response->headers->set('Content-Type', 'application/json');
$app->response->header('Access-Control-Allow-Headers',>
'Content-Type');
$app->response->header('Access-Control-Allow-Methods', 'GET, PUT,
POST, DELETE');
$app->response->header('Access-Control-Allow-Origin','*');
$app->get('/', function() use($app){
$ins = new Lead();
$products = $ins->run();
echo
json_encode($products);
});
If I use the crome extension then the header response from the server is as follows.
HTTP/1.1 200 OK Date: Wed, 16 Dec 2015 23:04:26 GMT Server:
Apache/2.4.7 (Ubuntu) X-Powered-By: PHP/5.5.9-1ubuntu4.14
Access-Control-Allow-Headers: Content-Type
Access-Control-Allow-Methods: GET, PUT, POST, DELETE
Access-Control-Allow-Origin: * Keep-Alive: timeout=5, max=100
Connection: Keep-Alive Transfer-Encoding: chunked Content-Type:
application/json
So the headers are being sent. But CORS still does not work without the extension. I need to fix this for all browsers of course. Not just mine. I'm pretty sure its a small mistake but I'm not seing it. What's wrong here?
Your system needs to handle "options" routes.
Browsers use an OPTIONS request at the same URL. So essentially you need to handle 2 requests.
If you add in a $app->options("/:name+"); it should fix it.
I am trying to create a RESTful web service and have gotten stuck on implementing PUT requests. I have tried and failed to follow other answers on this site and various articles from Mozilla.
The request is generated from the domain wwwtest.dev-box and it's going to test.dev-box (basically a front-end app calling the back-end app). Here are the headers I have captured from Live HTTP headers:
http://test.dev-box/resource/v1/data/user/1
OPTIONS /resource/v1/data/user/1 HTTP/1.1
Host: test.dev-box
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:24.0) Gecko/20100101 Firefox/24.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Origin: http://wwwtest.dev-box
Access-Control-Request-Method: PUT
Connection: keep-alive
HTTP/1.1 405 Method Not Allowed
Date: Wed, 16 Oct 2013 16:15:58 GMT
Server: Apache/2.2.15 (Red Hat)
x-powered-by: PHP/5.3.27
Access-Control-Allow-Origin: http://wwwtest.dev-box
Access-Control-Allow-Methods: POST, GET, PUT, OPTIONS
Access-Control-Max-Age: 1728000
Content-Length: 0
Allow: PUT
Cache-Control: no-cache
Connection: close
Content-Type: text/html; charset=UTF-8
I'm using a framework so everything is routed to web.php, which contains the following code at the top of the page (taken from this MDN article):
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
header('Access-Control-Allow-Origin: http://wwwtest.dev-box');
header('Access-Control-Allow-Methods: POST, GET, PUT, OPTIONS');
header('Access-Control-Max-Age: 1728000');
header("Content-Length: 0");
header("Content-Type: text/plain");
} else {
header("HTTP/1.1 403 Access Forbidden");
header("Content-Type: text/plain");
}
Before my code makes the PUT request it sends the CORS preflight OPTIONS request first (as you can see from the capture above). The necessary headers should be attached to the response and tell the requester that PUT is allowed. Unfortunately as you can see from the response headers above it is still returning 405 Method Not Allowed even though PUT is in the response access-control-allow-methods.
This is the .htaccess file for the framework I'm using (Silex):
<IfModule mod_rewrite.c>
Options -MultiViews
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ web.php [QSA,L]
</IfModule>
I've found the answer to be a cross between Apache and framework configuration.
For the Apache config you can either put the following into your VirtualHost directive, or in the .htaccess file of the requested domain (if it's in the .htaccess remember to encapsulate with IfModule mod_headers.c tags). Setting the headers on the page that mod_rewrite redirects to does not work:
Header set Access-Control-Allow-Origin "http://wwwtest.dev-box"
Header set Access-Control-Allow-Methods "GET,POST,HEAD,DELETE,PUT,OPTIONS"
For the Silex config, place the following into your application routes. It basically sends an HTTP 200 OK for any OPTIONS request it receives. Code found on the Silex Google Group:
$app->match("{url}", function($url) use ($app) {
return "OK";
})->assert('url', '.*')->method("OPTIONS");
Both steps need to be completed for the RESTful application to function properly.
The 405 is in reference to the actual preflight/OPTIONS request. Your server is rejecting the preflight outright as OPTIONS requests in general are not accepted by your server. You'll need to modify your server configuration to accept OPTIONS requests. Simply including code in a PHP file may not be enough. Most likely your web/application server is not aware of this verb and is rejecting the request before it hits your PHP code.