Skip to content

Instantly share code, notes, and snippets.

@danharper
Last active April 20, 2024 01:53
Show Gist options
  • Save danharper/06d2386f0b826b669552 to your computer and use it in GitHub Desktop.
Save danharper/06d2386f0b826b669552 to your computer and use it in GitHub Desktop.
Lumen with CORS and OPTIONS requests
<?php namespace App\Providers;
use Illuminate\Support\ServiceProvider;
/**
* If the incoming request is an OPTIONS request
* we will register a handler for the requested route
*/
class CatchAllOptionsRequestsProvider extends ServiceProvider {
public function register()
{
$request = app('request');
if ($request->isMethod('OPTIONS'))
{
app()->options($request->path(), function() { return response('', 200); });
}
}
}
<?php namespace App\Http\Middleware;
class CorsMiddleware {
public function handle($request, \Closure $next)
{
$response = $next($request);
$response->header('Access-Control-Allow-Methods', 'HEAD, GET, POST, PUT, PATCH, DELETE');
$response->header('Access-Control-Allow-Headers', $request->header('Access-Control-Request-Headers'));
$response->header('Access-Control-Allow-Origin', '*');
return $response;
}
}

Register the CatchAllOptionsRequestsProvider service provider in bootstrap/app.php which will check the incoming request and response successfully if it is an OPTIONS request.

Add the CorsMiddleware to the $app->middleware([ array in bootstrap/app.php which will attach the following CORS headers to all responses:

  • allow all headers
  • allow requests from all origins
  • allow all the headers which were provided in the request
@ccmelas
Copy link

ccmelas commented Nov 19, 2017

Wow...Finally... Thanks a lot

@nusendra
Copy link

It works. Thanks
So This is the perfect solution for me

  1. Create CatchAllOptionsRequestsProvider.php to App\Providers folder.
<?php namespace App\Providers;
use Illuminate\Support\ServiceProvider;
/**
 * If the incoming request is an OPTIONS request
 * we will register a handler for the requested route
 */
class CatchAllOptionsRequestsProvider extends ServiceProvider {
  public function register()
  {
    $request = app('request');
    if ($request->isMethod('OPTIONS'))
    {
      app()->options($request->path(), function() { return response('', 200); });
    }
  }
}
  1. Then create CorsMiddleware.php
<?php

namespace App\Http\Middleware;

use Closure;

class CorsMiddleware
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
		//Intercepts OPTIONS requests
		if($request->isMethod('OPTIONS')) {
			$response = response('', 200);
		} else {
			// Pass the request to the next middleware
			$response = $next($request);
		}

		// Adds headers to the response
		$response->header('Access-Control-Allow-Methods', 'HEAD, GET, POST, PUT, PATCH, DELETE');
		$response->header('Access-Control-Allow-Headers', $request->header('Access-Control-Request-Headers'));
		$response->header('Access-Control-Allow-Origin', '*');

		// Sends it
		return $response;
	}
}
  1. In bootstrap/app.php
    add this
$app->middleware([
   App\Http\Middleware\CorsMiddleware::class
]);

$app->register(App\Providers\CatchAllOptionsRequestsProvider::class);

Thanks to @danharper and @rgehan

@zhacarias
Copy link

Thanks a lot mate.. 👍

@lmj0011
Copy link

lmj0011 commented May 5, 2018

thanks @davidnknight @rgehan

You're right, all of this Middleware logic can be placed just in the middleware file and not also in a ServiceProvider.

ref:

https://gist.github.com/danharper/06d2386f0b826b669552#gistcomment-1694593

https://gist.github.com/danharper/06d2386f0b826b669552#gistcomment-2013919

@choyan
Copy link

choyan commented Sep 7, 2019

Thanks for summing it up @nusendra

@nusendra
Copy link

nusendra commented Sep 8, 2019

my pleasure bud @choyan

@yogenmohara
Copy link

Works for me. Many Thanks. :)

@skylineCodes
Copy link

Thanks very much for this

@rulatir
Copy link

rulatir commented Apr 8, 2020

Could you please explain how this solution can possibly be correct? My understanding is that OPTIONS exists in the HTTP standard for a reason. Carelessly stubbing it to a no-op must eventually have Dire Consequences, right?

@seinshah
Copy link

seinshah commented Jun 8, 2020

My solution was creating CorsMiddleware as below:

<?php

/**
 * Location: /app/Http/Middleware
 */
namespace App\Http\Middleware;

use Closure;

class CorsMiddleware
{
	/**
	 * Handle an incoming request.
	 *
	 * @param  \Illuminate\Http\Request  $request
	 * @param  \Closure  $next
	 * @return mixed
	 */
	public function handle($request, Closure $next)
	{
		$headers = [
			'Access-Control-Allow-Origin' => '*',
			'Access-Control-Allow-Methods' => 'POST,GET,PATCH,PUT,DELETE,OPTIONS',
			'Access-Control-Max-Age' => '86400',
                        'Access-Control-Allow-Headers' => 'Content-Type,API-KEY'
                ];

		if ($request->isMethod('OPTIONS')) {
			return response()->json('', 200, $headers);
		}

		$response = $next($request);

		foreach ($headers as $key => $value) {
			$response->header($key, $value);
		}

		return $response;
	}
}

Then register the middleware with a name in bootstrap/app.php as below:

$app->routeMiddleware([
  'cors' => App\Http\Middleware\CorsMiddleware::class
]);

Then wrapping required routes between the defined middleware in routes/web.php as below, and adding an additional rule to handle preflight OPTIONS requests:

$router->group(['middleware' => 'cors'], function () use ($router) {
  //All the routes you want to allow CORS for

  $router->options('/{any:.*}', function (Request $req) {
    return;
  });
});

NOTE
Using Chrome, you can get a more detailed error message than Firefox, which will help you to fix the problem and exactly states why there is no Access-Control-Allow-Origin in the response header. Also, keep in mind that any kind of redirect is not allowed in the preflight request, so make sure you don't have such rule in your .htaccess or any other place.

@JhonLimbong17
Copy link

My solution was creating CorsMiddleware as below:

<?php

/**
 * Location: /app/Http/Middleware
 */
namespace App\Http\Middleware;

use Closure;

class CorsMiddleware
{
	/**
	 * Handle an incoming request.
	 *
	 * @param  \Illuminate\Http\Request  $request
	 * @param  \Closure  $next
	 * @return mixed
	 */
	public function handle($request, Closure $next)
	{
		$headers = [
			'Access-Control-Allow-Origin' => '*',
			'Access-Control-Allow-Methods' => 'POST,GET,PATCH,PUT,DELETE,OPTIONS',
			'Access-Control-Max-Age' => '86400',
                        'Access-Control-Allow-Headers' => 'Content-Type,API-KEY'
                ];

		if ($request->isMethod('OPTIONS')) {
			return response()->json('', 200, $headers);
		}

		$response = $next($request);

		foreach ($headers as $key => $value) {
			$response->header($key, $value);
		}

		return $response;
	}
}

Then register the middleware with a name in bootstrap/app.php as below:

$app->routeMiddleware([
  'cors' => App\Http\Middleware\CorsMiddleware::class
]);

Then wrapping required routes between the defined middleware in routes/web.php as below, and adding an additional rule to handle preflight OPTIONS requests:

$router->group(['middleware' => 'cors'], function () use ($router) {
  //All the routes you want to allow CORS for

  $router->options('/{any:.*}', function (Request $req) {
    return;
  });
});

NOTE
Using Chrome, you can get a more detailed error message than Firefox, which will help you to fix the problem and exactly states why there is no Access-Control-Allow-Origin in the response header. Also, keep in mind that any kind of redirect is not allowed in the preflight request, so make sure you don't have such rule in your .htaccess or any other place.

I've tried all of the code, and LOL, no one work for me.
image

I'm still got this error

@saydin
Copy link

saydin commented Aug 11, 2021

Ekran Alıntısı

@saydin
Copy link

saydin commented Aug 11, 2021

hello everyone. I have cors middleware in my lumen as above. cors midlleware works normally when i make a request to lumen from my app. however, whenever a function that I need to send mail runs, I get the error "Call to a member function header() on null".

@rvalitov
Copy link

rvalitov commented Oct 8, 2021

A single file solution with CorsMiddleware.php worked like a charm with Lumen 8.x. The only issue I had that my .htaccess file was not default and was adjusted with the following command:

RewriteCond %{REQUEST_METHOD} OPTIONS
RewriteRule ^(.*)$ $1 [R=200,L]

In my case I had to remove these lines to make things work.

@saydin
Copy link

saydin commented Oct 8, 2021

Hello everyone again. I solved my error related to this issue. I share my answer with you below.

image
Due to the middleware structure, it returns and switches to the next request after processing. If an error is encountered after the request middleware has passed and did not return, the return value will be null.

For example, after I pass the request from the cors middleware, I am sending a mail via a event as a result of a series of operations. However, even though I changed the mail blade I sent, the cors middleware response value returns null because the php document created in ~/storage/framework/views does not update, and an error occurs.

https://stackoverflow.com/questions/68739232/call-to-a-member-function-header-on-null-in-cors-middleware-in-lumen/68760328#68760328

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment