【问题标题】:Laravel Cors (Middleware NOT working)Laravel Cors(中间件不工作)
【发布时间】:2017-09-10 16:43:59
【问题描述】:

我最近尝试在 Laravel 5.4 中启用 CORS,但不幸的是它不想工作。我在下面包含了代码和它给我的错误。谁能帮助找出它为什么不起作用?我已通过所需的标头。

我已将我的域重命名为 domain.uk 只是为了举例,我不想公开我的网站的域,因为它正在开发中。

Routes(在开发时为测试目的制作了一条路线 ::any,通常在生产时发布):

Route::group(['domain' => 'api.domain.uk', 'namespace' => 'Api'], function() {
    Route::group(['middleware' => ['cors'], 'prefix' => 'call'], function() {
        Route::get('/rooms/{id}/get-locked-status', 'ApiController@getRoomLockStatus');
        Route::any('/rooms/{id}/update-locked-status', 'ApiController@updateRoomLockStatus');
    });
});

错误:

XMLHttpRequest cannot load http://api.domain.uk/ajax/rooms/1/update-locked-status. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://ice.domain.uk' is therefore not allowed access. The response had HTTP status code 500.

中间件:

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)
    {
        return $next($request)
            ->header('Access-Control-Allow-Origin', '*')
            ->header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS')
            ->header('Access-Control-Allow-Headers', 'Content-Type, Accept, Authorization, X-Requested-With, Application');
    }
}

阿贾克斯:

function toggleDoors(roomId) {
    $.ajax({
        url: 'http://api.domain.uk/ajax/rooms/' + roomId + '/update-locked-status',
        type: "POST",
        success: function(data) {
            alert(data);
        }
    });
}

ApiController:

<?php
namespace App\Http\Controllers\Api;

use Auth;
use App\User;
use App\Http\Controllers\Controller;
use Validator;
use Redirect;
use Illuminate\Http\Request;
use App\Database\Frontend\Other\Rooms;

class ApiController extends Controller
{
    public function getRoomLockStatus($id) {
        $room = Rooms::find($id);

        if ($room == null) {
            return response('bad request', 400);
        } 
        else {
            return $room->rp_locked;
        }
    }

    public function updateRoomLockStatus(Request $request, $id) {
        $room = Rooms::find($id);

        if ($room == null) {
            return response('bad request', 400);
        } 

        $room->rp_locked = $room->rp_locked == '1' ? '0' : '1';
        $room->save();

        $responseText = $room->rp_locked == '1' ?
            'Your doors have been locked.' : 'Your doors have been unlocked.';

        return response($responseText, 200);
    }
}

【问题讨论】:

  • 您是否更新了 /app/Http/Kernel.php 中的 $routeMiddleware 变量以包含新的 cors 中间件?
  • 是的,我做到了......
  • 我找到了一个解决方案,它允许将您的 CORS 库仅应用于端点子集(出于安全原因)而不使用任何外部库:stackoverflow.com/questions/34748981/…

标签: php laravel


【解决方案1】:

https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/OPTIONS#Preflighted_requests_in_CORS

如果您在 OPTIONS 方法中遇到问题。

Kernel::$routeMiddleware 在 Laravel 5.4 中不能用于请求方法 OPTIONS,请参阅 https://github.com/laravel/framework/blob/v5.4.0/src/Illuminate/Routing/RouteCollection.php#L214。 要使用 CORS 中间件,请在 Kernel::$middleware 数组中启用它。这不好,但没有别的办法。

例如,我为 SPA 和 API 使用下一个中间件类,注意,它不是用于路由的中间件 'cors'

<?php
namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Illuminate\Http\Response;

/**
 * OptionsCorsResponse middleware - add CORS headers if request method OPTIONS
 */
class OptionsCorsResponse
{
    /**
     *
     * @param Request $request
     * @param Closure $next
     * @return Response
     */
    public function handle($request, Closure $next)
    {
        /* @var $response Response */
        $response = $next($request);
        if (!$request->isMethod('OPTIONS')) {
            return $response;
        }
        $allow = $response->headers->get('Allow'); // true list of allowed methods
        if (!$allow) {
            return $response;
        }
        $headers = [
            'Access-Control-Allow-Methods' => $allow,
            'Access-Control-Max-Age' => 3600,
            'Access-Control-Allow-Headers' => 'X-Requested-With, Origin, X-Csrftoken, Content-Type, Accept',
        ];
        return $response->withHeaders($headers);
    }
}

并在 App\Http\Kernel 中启用它

protected $middleware = [
    // ...
    \App\Http\Middleware\OptionsCorsResponse::class,
];

起源'http://ice.领域 。 uk' 因此是不允许的 使用权。响应的 HTTP 状态代码为 500。

调试您的代码,因为它会产生一些异常。使用任何带有 OPTIONS 方法的 REST 客户端。

【讨论】:

    【解决方案2】:

    在CORS中,浏览器首先发送OPTIONS请求到指定路由。

    在 CORS 中,发送一个带有 OPTIONS 方法的预检请求,以便服务器可以响应是否可以接受发送带有这些参数的请求: https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/OPTIONS

    所以像这样改变你的中间件:

    public function handle($request, Closure $next)
        {
            if ($request->isMethod('OPTIONS')){
                $response = Response::make();
            } else {
                $response = $next($request);
            }
            return $response
                ->header('Access-Control-Allow-Origin', '*')
                ->header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS')
                ->header('Access-Control-Allow-Headers', 'Content-Type, Accept, Authorization, X-Requested-With, Application');
        }
    

    如果您想在路由中允许其他标头,请将它们添加到 'Access-Control-Allow-Headers' 标头字段中。

    【讨论】:

    • 这也不起作用。我仍然遇到与其他人回答时相同的错误。 XMLHttpRequest 无法加载 api.domain.uk/ajax/rooms/1/update-locked-status。对预检请求的响应未通过访问控制检查:请求的资源上不存在“Access-Control-Allow-Origin”标头。起源'ice.domain.uk';因此不允许访问。
    • 你把路由的前缀改成ajax了吗?
    • 你是把包去掉还是还在用?
    • 我删除了包。
    • 您必须需要从您的控制器发送Response 对象。如果您在控制器中或两者之间的任何地方倾倒任何东西,则需要将其删除。
    【解决方案3】:

    您可以通过在 bootstrap/app.php 中添加标头轻松完成此操作

    header('Access-Control-Allow-Origin: *');
    header('Access-Control-Allow-Methods: *');
    header('Access-Control-Allow-Headers: *');
    

    【讨论】:

      【解决方案4】:

      如果这些都不起作用,请在 apache 虚拟主机配置中添加 cors(如果您使用虚拟主机)。

      转到/etc/apache2/sites-available 并添加类似this gist 的内容

      然后sudo a2ensite example.confsudo service apache2 reload ;)

      【讨论】:

        【解决方案5】:

        我最近突然遇到了一个不是由 CORS 标头配置引起的 CORS 问题,我发现了以下内容:

        有些红鲱鱼场景也可能导致显示 CORS 跨域错误,但与 CORS 配置没有任何关系,这是由于中间件处理 CORS 而其他因素阻止它被触发的结果。

        以下情况可能会间接导致错误显示在浏览器响应中:

        • 中间件类中的 PHP 错误。
        • return $next($request); 没有在中间件类方法handle 中被触发。
        • Route::middleware 在 web 或 api 路由器配置中引用了一个不再存在或拼写错误的中间件。
        • 与上述相同,但中间件在控制器中指定为$this-&gt;middleware();

        任何这些都可以防止 Cors 中间件被触发,因为应用程序退出过早并且从不设置标头,因此由于中间件文件或引用错误导致 CORS 错误而不是 500 服务器标头错误到中间件。

        如果您确定您已正确配置 CORS,那么您应该 检查您的 PHP 错误日志以查找中间件错误。

        【讨论】:

          【解决方案6】:

          我正在使用 Laravel 6 及更高版本。这个网址帮助我解决了我的 CORS 问题:https://medium.com/@petehouston/allow-cors-in-laravel-2b574c51d0c1

          使用此代码代替 url 中的代码:

          <?php
          
          namespace App\Http\Middleware;
          
          use Closure;
          
          class Cors
          {
              public function handle($request, Closure $next)
              {
          
                    return $next($request)
                        ->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,X-Token-Auth, Authorization');
              }
          }
          

          另外,如果您想在整个应用程序中使用中间件,那么您需要在 Kernel.php 中进行更改:

          protected $middleware = [
          \App\Http\Middleware\Cors::class, //add this line to $middleware variable
          ]
          

          【讨论】:

            【解决方案7】:

            我在使用 withHeaders() 方法处理文件时遇到了问题,因此感谢下面的提示,我想出了这个工作代码:

            /**
                 * Handle an incoming request.
                 *
                 * @param  \Illuminate\Http\Request  $request
                 * @param  \Closure  $next
                 * @return mixed
                 */
                public function handle($request, Closure $next)
                {
                    if ($request->isMethod('OPTIONS'))
                    {
                        return response()->json('{"method":"OPTIONS"}', 200, $headers);
                    }
            
                    $response = $next($request);
                    $response->headers->set('Access-Control-Expose-Headers', 'Content-Disposition');
                    $response->headers->set('Access-Control-Allow-Origin', 'http://localhost:8080','http://localhost','https://edu.pilateswien.org');
                    $response->headers->set('Access-Control-Allow-Methods', 'GET, POST, PUT, PATCH, DELETE, OPTIONS');
            
                    //return $response->withHeaders($headers);
                    return $response;
                }
            

            【讨论】:

              【解决方案8】:

              Sergei 是对的,问题是由于预检请求引起的:https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/OPTIONS#Preflighted_requests_in_CORS

              因此,仅向一组端点添加中间件是行不通的,因为预检使用的是 OPTION 方法而不是 GET 方法。

              这个package 正好解决了这个问题,通过在你的内核中为所有路由放置一个中间件,然后你在config/cors.php 中过滤你想要允许CORS 的路由。 因此,您还可以处理 option 方法附带的预检请求。

              简而言之,安装包:

              composer require fruitcake/laravel-cors
              

              将中间件放入你的中间件数组中:

              protected $middleware = [
                \Fruitcake\Cors\HandleCors::class,
                  // ...
              ];
              

              发布配置文件:

              php artisan vendor:publish --tag="cors"
              

              并在config/cors 内的paths 中指定您希望允许哪些路由(或仅一个路由):

              'paths' => ['api/*'],
              

              另请参阅blog post 了解更多信息。

              【讨论】:

                【解决方案9】:

                只需在您的路线上添加此代码

                header('Access-Control-Allow-Origin: http://yourdomain.com/');
                

                【讨论】:

                  猜你喜欢
                  • 2016-05-26
                  • 2020-03-08
                  • 2013-11-14
                  • 2018-07-07
                  • 2017-07-20
                  • 1970-01-01
                  • 2018-12-30
                  • 2019-02-22
                  相关资源
                  最近更新 更多