Laravel API return HTTP 0 error - ajax

I access my Laravel API Endpoints with respective Params its return HTTP 0 Error.
$(document).ready(function() {
$('#customer_name').change(function() {
$.ajax({
url: "http://acmexponents.com/api/v1/untransportamts",
dataType: "json",
type: "POST",
data: {
'pickupaddress': 'Ampang Jaya Selangor Malaysia',
'deliveryaddress': 'Bukit Bintang Kuala Lumpur Federal Territory of Kuala Lumpur Malaysia',
'pickupdate': '2018-01-24',
'pickuptime': '14:30',
'vehicletype': 2,
'vehiclesize': 3,
},
success: function(response) {
$("#customer_address").val(json);
},
error: function(jqXHR, textStatus, errorThrown) {
alert(jqXHR.status);
alert(textStatus);
alert(errorThrown);
}
});
});
});
Full Error Text :
Javascript returned an HTTP 0 error. One common reason this might
happen is that you requested a cross-domain resource from a server
that did not include the appropriate CORS headers in the response.
Better open up your Firebug...
How to resolve It.

What is CORS (Cross-origin resource sharing):
We understand that Javascript is restricted by same origin policy, i.e, could not make request that crossed its origin (different domain name etc). This is troublesome for web owners that is having different domain name as their web service although everything is owned by the same owner.
To bypass same origin policy, CORS is introduced such that a web server can explicitly allow javascript from making requests although the origin has crossed. It can be achieved by either from Apache, PHP, or any http proxies, whichever is capable in sending response headers will be able to implement this mechanism.
https://en.wikipedia.org/wiki/Cross-origin_resource_sharing
There are couple ways sending CORS headers to your app. One option is to include a middleware that emits CORS headers to every requests. This class ensured your server allow everyone to make request to this server (not very recommended, tweak as you like).
Create new file app/Http/Middleware/CorsMiddleware.php
class CorsMiddleware
{
public function handle($request, \Closure $next)
{
$headers = [
'Access-Control-Allow-Origin' => '*',
'Access-Control-Allow-Methods' => 'POST, GET, OPTIONS, PUT, DELETE',
'Access-Control-Allow-Credentials' => 'true',
'Access-Control-Max-Age' => '86400',
'Access-Control-Allow-Headers' => 'Content-Type, Authorization, X-Requested-With'
];
if ($request->isMethod('OPTIONS')) {
return response()->json('{"method":"OPTIONS"}', 200, $headers);
}
$response = $next($request);
foreach ($headers as $key => $value) {
$response->header($key, $value);
}
return $response;
}
}
If you are using Lumen, include the middleware in your app.php:
$app->middleware([
//...
App\Http\Middleware\CorsMiddleware::class,
//...
]);
CORS Middleware source code: https://gist.github.com/danharper/06d2386f0b826b669552#gistcomment-1694593

Related

Laravel Echo + Websockets + Private Channels

I know I'm not the first struggling with this. But after some days and going trough a lot of related questions i somehow feel that my case deserves it's own question :).
I have a working websocket solutions with Laravel Websockets (https://beyondco.de/docs/laravel-websockets/getting-started/introduction) and Laravel Echo for public channels.
My client application is a vue-cli app and connects to the server + broadcast messages on public channels work great. The authorization is handled by Laravel Passport. So through sending a Bearer token in the Authorization header the backend application knows if the user is authenticated.
However I'm struggling to get Private channels to work. Trying to authenticate always gives me this error:
Access to XMLHttpRequest at 'https://my-app.test/broadcasting/auth' from origin 'https://localhost:8080' 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.
I know this CORS error comes on my way when I have a server issues so I tried debugging the request in Insomnia. However when mimicking the request in Insomnia it gives a response 200 and also what would be expected:
I've been reading several guides and stackoverflow questions but I can't find anything similar.
Going back to it might be a CORS issues but I don't think that is the case. My OPTIONS request returns back just fine.
To be complete I also add some code that might help in debugging.
My BroadcastServiceProvider
public function boot()
{
Broadcast::routes(['middleware' => ['auth:api']]);
require base_path('routes/channels.php');
}
My channels.php
use Illuminate\Support\Facades\Broadcast;
Broadcast::channel('App.User.{id}', function ($user, $id) {
return (int) $user->id === (int) $id;
});
The client
this.echoClient = new Echo({
broadcaster: 'pusher',
key: process.env.VUE_APP_WEBSOCKETS_APP_ID,
wsHost: process.env.VUE_APP_WEBSOCKETS_URL,
wssPort: 6001,
// forceTLS: true,
disableStats: true,
authEndpoint: process.env.VUE_APP_SERVER_URL + '/broadcasting/auth',
auth: {
headers: {
Authorization: "Bearer " + this.$store.state.auth.auth_token
}
}
})
// this one works!!
this.echoClient.channel('App.User')
.listen('UpdatePosts', (e) => {
console.log('event received')
console.log(e)
})
// private channels don't work ... :'(
this.echoClient.private('App.User.' + this.user.id)
.listen('UpdatePosts', function(e) {
console.log(e)
})
for anyone struggling with this issue.
For me the solution was to add the api prefix to the broadcast::auth method.
public function boot()
{
Broadcast::routes(['prefix' => 'api', 'middleware' => ['auth:api']]);
require base_path('routes/channels.php');
}
Offcourse you need to correctly set the api prefix on the client:
authEndpoint: process.env.VUE_APP_SERVER_URL + '/api/broadcasting/auth',
I suppose the difference is that when you prefix api Laravel we specifically tell the server to ditch web Middleware.
I still don't really understand why the request was succesfull from Insomnia since there was no x-csrf header set. Insomnia did send a cookie header. Maybe that's the reason why it was working there.
EDIT
Solution provide by #Tippin on laracasts forum.
To add to the answer, it was a CORS issue after all.
https://github.com/fruitcake/laravel-cors
Prefixing the broadcast route with API does not alter middleware at all, so that is not putting it in the api middleware group. What I do think is happening is you may have the cors package installed and in the allowed paths, you have something like api/*, so by simply adding that prefix, you solved your issue. Otherwise, you can add the default broadcast to the whitelist (assuming you use that package for CORS):
/*
* You can enable CORS for 1 or multiple paths.
* Example: ['api/*']
*/
'paths' => ['api/*', 'broadcasting/auth'],
https://github.com/fruitcake/laravel-cors/blob/master/config/cors.php
I've got the same problem
By using fruitcake/laravel-cors, it was solved.
this is my auth option:
auth : {
headers : {
Authorization: "Bearer " + token,
Accept: "application/json",
}
},

Enable CORS on Lumen API

I know it's a known issue but I've tried almost everything and I'm still stuck on this. I have a simple project structured like this:
[Client] => [Gateway] => [API]
Laravel 6 Lumen 6 Lumen 6
localhost:8000 localhost:8001 localhost:8002
Since I'm just started working on this project only to prove if this works I've disabled all auth stuff.
On my API I have a folder within public called uploads (Basically in http://localhost:8002/uploads/audio.amr) where I have 1 audio file (.amr) and I'm trying to play it from a client view.
Since html can't play .amr files, I had to use a plugin. And I'm using this one BenzAMRRecorder.
[Client side]
I make an ajax petition to get the url of the audio file. The client through guzzle connects with the gateway and the gateway also does it with the API and I successfully got the url http://localhost:8002/uploads/audio.amr.
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
$.ajax({
url : 'client/get_url_audio',
type : 'GET',
data : {
},
dataType:'json',
success : function(data) {
/** Here's the way to play the file */
var amr = new BenzAMRRecorder();
amr.initWithUrl(data['url']).then(function() {
amr.play();
});
},
});
I successfully got the url but when the BenzAMRRecorder try to access to the url http://localhost:8002/uploads/audio.amr I got this error:
The error:
Access to XMLHttpRequest at 'http://localhost:8002/uploads/audio.amr' from origin 'http://localhost:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
I've read a lot of ways to fix this and I added a CorsMiddleware on the API with a handle function as follows:
public function handle($request, Closure $next)
{
$headers = [
'Access-Control-Allow-Origin' => '*',
'Access-Control-Allow-Methods' => 'POST, GET, OPTIONS, PUT, DELETE',
'Access-Control-Allow-Credentials' => 'true',
'Access-Control-Max-Age' => '86400',
'Access-Control-Allow-Headers' => 'Content-Type, Authorization, X-Requested-With'
];
if ($request->isMethod('OPTIONS'))
{
return response()->json('{"method":"OPTIONS"}', 200, $headers);
}
$response = $next($request);
foreach($headers as $key => $value)
{
$response->header($key, $value);
}
return $response;
}
And then on bootstrap/app.php added
$app->middleware([
App\Http\Middleware\Cors::class
]);
But I'm still getting the same error. The thing I thought is that, when the method amr.initWithUrl(data['url']) access to the API folder, it doesn't go to middleware and try to access directly to the folders without passing by the middleware but I don't know why. Can someone help me to solve this problem?
EDIT: I also tried with github.com/barryvdh/laravel-cors
Add the following in the .htaccess file from the server which holds the resource you are trying to access:
Header Set Access-Control-Allow-Origin "*"
I don't know if it works in Lumen, but for Laravel, I've had a lot of success using this neomerx/cors package.
You probably missed the header X-CSRF-TOKEN from your CORS middleware?
$headers = [
....
// You will need to add ALL headers sent from your client
'Access-Control-Allow-Headers' => 'Content-Type, Authorization, X-Requested-With, X-CSRF-TOKEN'
];

CORS Access to XMLHttpRequest at X from origin has been blocked by CORS policy

CORS Access to XMLHttpRequest at X from origin has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status.
Hi, I am struggling to resolve my problems with CORS denying interaction of my Vue component with an external API with axios since it returns this error. I've tried both using Barryvdh's Cors header support and making a middleware and custom route. It simply won't work. Everything that has been mentioned in README.md in Barryvdh's repo has been done and unfortunately, this problem won't get resolved by any means necessary.
Here is the code, even though I don't think there's need to show since it's exactly the same as mentioned in the repo;
inside Kernel.php:
protected $middleware = [
\Barryvdh\Cors\HandleCors::class,
inside app.php (providers array):
Barryvdh\Cors\ServiceProvider::class,
config/cors.php:
'supportsCredentials' => false,
'allowedOrigins' => ['*'],
'allowedHeaders' => ['*'],
'allowedMethods' => ['*'], // ex: ['GET', 'POST', 'PUT', 'DELETE']
'exposedHeaders' => [],
'maxAge' => 0,
Here's the axios get call (I've replaced my token with 'TOKEN')
methods: {
loadWeatherData: function() {
axios.get( 'http://api.openweathermap.org/data/2.5/weather?q=London&mode=json&units=metric&appid=TOKEN' )
.then( function( response ) {
console.log( 'radi' );
}).catch( errors => {
console.log( errors+' ne radi');
});
}
},
I've composer dump-ed, nothing affected resolving the problem.
Is there something I am doing wrong and are there any solutions for this problem? Thanks in advance!
The problem here seems to be that axios likes to send its own default headers, and these don't pass the preflight check for your external request. To fix this, you will need to remove the offending headers.
I was able to recreate your error, and also to bypass the CORS issue using the code below.
let url = 'https://api.openweathermap.org/data/2.5/weather?q=London&mode=json&units=metric&appid=TOKEN';
// create a new instance so we don't delete the headers for other requests
let instance = axios.create();
// delete headers if existing
delete instance.defaults.headers.common['Accept'];
delete instance.defaults.headers.common['X-Requested-With'];
delete instance.defaults.headers.common['X-CSRF-TOKEN'];
// use the new axios instance to make your get request
instance.get(url)
.then(function(response) {
console.log(response);
}).catch( errors => {
console.log(errors + ' ne radi');
});
Hope this helps and good luck!
You can add into TrustHosts.php Middleware without doing anything extra. Read more from here https://stackoverflow.com/a/70361284/2612926

Magento 401 on API request after setting headers for cross origin

I am trying to call the web API for products in Magento from a React Native app. After other stack exchange question & answers plus tutorials I am still receiving a 401 response. I know the call works because I can make it through postman.
Update: So I did not solve it, however I have found that if I use axios the request will work. This seems to be an issue with fetch.
.htaccess mod_headers.c settings
Header set Access-Control-Allow-Origin "*"
Header set Access-Control-Allow-Headers "Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With"
Header set Access-Control-Allow-Methods "POST, GET, PUT, OPTIONS"
app/etc/env.php
'x-frame-options' => 'CROSS-ORIGIN'
API Call from React Native
fetch(
'http://localhost:8888/magento/rest/V1/products?searchCriteria[filter_groups][0][filters][0][field]=name&searchCriteria[filter_groups][0][filters][0][value]=product name',
{
method: 'GET',
headers: {
'Content-Type': 'application/json',
Authentication: 'Bearer fwynACCESS_TOKENbal9tfr'
}
}
)
.then((res) => {
if (res.status !== 200 && res.status !== 204)
reject({ message: 'There was an error with the products service' })
resolve(res.json())
})
.catch((err) => reject(err))
This also includes a web integration named Customers with all the API options set as accessible.

Method PUT is not allowed by Access-Control-Allow-Methods in preflight response vue-laravel App

I am new in vue. For ajax request I am using axios and for back-end I am using Laravel. Whenever I send a POST and GET request it's works fine. But while trying to send a PUT Request its showing Method PUT is not allowed by Access-Control-Allow-Methods in preflight response vue-laravel App. I had read lots of answer in Stackoverflow and github but none of them worked for me.
Here is the client side code:
axios.put('http://127.0.0.1:8000/api/photo/6', this.photo, { headers: getHeader() })
.then(response => {
console.log(response.data.message);
}).catch(err => {
this.errors = err.response.data.errors;
});
Here is CROSS middleware code:
//allowed client
//now only for localhost vue cli
$domains = ['http://localhost:8080'];
if(isset($request->server()['HTTP_ORIGIN'])){
$origin = $request->server()['HTTP_ORIGIN'];
if(in_array($origin, $domains)){
header('Access-Control-Allow-Origin: '.$origin);
header('Access-Control-Allow-Headers: Origin, Content-Type, Authorization');
}
}
return $next($request);
Try this in backend :
app/Http/Middleware/Cors.php
public function handle($request, Closure $next)
{
return $next($request)
->header('Access-Control-Allow-Origin', '*')
->header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE,
OPTIONS');
}
app/Http/Kernel.php $routedMiddleware array add
'cors' => \App\Http\Middleware\Cors::class,
Route/api.php
Route::group(['middleware' => 'cors'], function () {
Route::put('/v1/employees', 'Employees#store');
});
Particular GET, HEAD and POST HTTP requests do not trigger the CORS preflight OPTIONS check. They are called Simple Requests. They only send a subset of HTTP headers along. Any other additional header, like an Authorization header (think JWT authentication), will trigger a preflight OPTIONS request. The details on this can be found on https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
I think the easiest way for you to work with this, is to use the laravel-cors package on the backend (see https://github.com/barryvdh/laravel-cors).
While doing development, you can simply be very permissive by setting allowedOrigins, allowedHeaders and allowedMethods to *. Later on, during testing and subsequently production, you should tune it to be more strict. By that time you'll have a much better hang of CORS concepts, and then you can configure it fully to your needs.

Resources