Laravel 5.1 API启用Cors

49

是的,我已经尝试过了,但我仍然收到以下消息(这是一个Angular前端):XMLHttpRequest无法加载http://api.address.com。请求的资源上没有'Access-Control-Allow-Origin'标头。因此,不允许从源'http://127.0.0.1:8080'访问。但我已经在cors文件中添加了本地地址'supportsCredentials' => true, 'allowedOrigins' => ['http://127.0.0.1:8080'], 'allowedHeaders' => ['*'], 'allowedMethods' => ['GET', 'POST', 'PUT', 'DELETE'], 'exposedHeaders' => [], 'maxAge' => 0, 'hosts' => []。 - Leonardo Lobato
XMLHttpRequest无法加载api.address.com。所请求的资源上没有“Access-Control-Allow-Origin”标头。因此,来自'127.0.0.1:8080'的源不被允许访问。 - Leonardo Lobato
你是否发布了配置文件并相应地进行了编辑? - rdiz
你有在浏览器中查看响应头吗?Access-Control-Allow-Origin 头应该设置为正确的域。此外,您可以尝试手动在一个路由上设置它... - Kjell
Access-Control-Allow-Credentials → true Access-Control-Allow-Headers → Origin, Content-Type, Accept, Authorization, X-Request-With Access-Control-Allow-Methods → GET, POST, OPTIONS Access-Control-Allow-Origin → *CORS似乎正在工作,我已经尝试使用本地主机代替*,但仍然无法正常工作。 - Leonardo Lobato
显示剩余2条评论
9个回答

93

这是我的CORS中间件:

<?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)
    {

        header("Access-Control-Allow-Origin: *");

        // ALLOW OPTIONS METHOD
        $headers = [
            'Access-Control-Allow-Methods'=> 'POST, GET, OPTIONS, PUT, DELETE',
            'Access-Control-Allow-Headers'=> 'Content-Type, X-Auth-Token, Origin'
        ];
        if($request->getMethod() == "OPTIONS") {
            // The client-side application can set only headers allowed in Access-Control-Allow-Headers
            return Response::make('OK', 200, $headers);
        }

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

}

要使用 CORS 中间件,您需要首先在您的 app\Http\Kernel.php 文件中注册它,像这样:

protected $routeMiddleware = [
        //other middlewares
        'cors' => 'App\Http\Middleware\CORS',
    ];

然后您可以在您的路由中使用它。

Route::get('example', array('middleware' => 'cors', 'uses' => 'ExampleController@dummy'));
编辑:在 Laravel ^8.0 中,您需要导入控制器的命名空间并像这样使用该类:
use App\Http\Controllers\ExampleController;

Route::get('example', [ExampleController::class, 'dummy'])->middleware('cors');

4
请说明一下 - 这是否是问题中提到的包的替代选择? - retrograde
6
如果你选择这个解决方案,就不需要使用一个包。 - Alex Kyriakidis
2
这是一个非常好的解决方案,还有 OPTIONS 方法来检查是否允许 Origin - 就像在中间件中一样 - 但由于某些原因,我无法在 Laravel 5.X 中运行所有 POST 方法 - 有什么想法吗? - Ole K
10
请注意,对于我来说,版本是5.6,并且我还需要在Kernel.php中protected $middleware数组内添加\App\Http\Middleware\Cors::class。如果有人和我一样遇到困难,可以尝试这个方法。 - arikanmstf
1
@arikanmstf,你让我这一周都很开心!!这就是我在CORS方面遇到的问题。你说得对,在kernel.php中将其添加到受保护的$middleware中就解决了!非常感谢。 - Delmontee
显示剩余11条评论

50

我总是使用一种简单的方法。只需将以下行添加到\public\index.php文件中即可。 我认为你不必使用中间件。

header('Access-Control-Allow-Origin: *');  
header('Access-Control-Allow-Methods: GET, PUT, POST, DELETE, OPTIONS');

19
不够优雅 - Efriandika Pratama
6
为什么不呢?index.php文件在所有HTTP请求中都被使用,这是一种简单且用户友好的方式。 - Joel James
21
@EfriandikaPratama 反复重复一件事情并不能证明你的观点。 - Anthony
11
如果您希望为整个应用程序启用CORS,则这是一个不错的选择,但如果您只想在某些路由上启用CORS,则该选项并不适用。我认为使用中间件更为合理。 - MM2
3
我认为当所有路由已经通过OAuth或JWT进行保护时,使用中间件进行保护是不必要的。简短明了。 - ronaldtgi
显示剩余4条评论

13
我正在使用 Laravel 5.4,但遗憾的是,虽然被接受的答案看起来很好,但对于预检请求(如 PUTDELETE),这些请求将在一个 OPTIONS 请求之前进行,如果在 $routeMiddleware 数组中指定中间件(并在路由定义文件中使用该中间件),则无法工作,除非您还为 OPTIONS 定义了一个路由处理程序。这是因为没有 OPTIONS 路由,Laravel 将会在没有 CORS 标头的情况下内部响应该方法。
简而言之,要么在 $middleware 数组中定义全局运行的中间件,要么在 $middlewareGroups$routeMiddleware 中进行定义,并同时为 OPTIONS 定义一个路由处理程序。可以像这样实现:
Route::match(['options', 'put'], '/route', function () {
    // This will work with the middleware shown in the accepted answer
})->middleware('cors');

我也为相同目的编写了一个中间件,看起来类似,但体积更大,因为它试图更加可配置并处理一堆条件:

<?php

namespace App\Http\Middleware;

use Closure;

class Cors
{
    private static $allowedOriginsWhitelist = [
      'http://localhost:8000'
    ];

    // All the headers must be a string

    private static $allowedOrigin = '*';

    private static $allowedMethods = 'OPTIONS, GET, POST, PUT, PATCH, DELETE';

    private static $allowCredentials = 'true';

    private static $allowedHeaders = '';

    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
      if (! $this->isCorsRequest($request))
      {
        return $next($request);
      }

      static::$allowedOrigin = $this->resolveAllowedOrigin($request);

      static::$allowedHeaders = $this->resolveAllowedHeaders($request);

      $headers = [
        'Access-Control-Allow-Origin'       => static::$allowedOrigin,
        'Access-Control-Allow-Methods'      => static::$allowedMethods,
        'Access-Control-Allow-Headers'      => static::$allowedHeaders,
        'Access-Control-Allow-Credentials'  => static::$allowCredentials,
      ];

      // For preflighted requests
      if ($request->getMethod() === 'OPTIONS')
      {
        return response('', 200)->withHeaders($headers);
      }

      $response = $next($request)->withHeaders($headers);

      return $response;
    }

    /**
     * Incoming request is a CORS request if the Origin
     * header is set and Origin !== Host
     *
     * @param  \Illuminate\Http\Request  $request
     */
    private function isCorsRequest($request)
    {
      $requestHasOrigin = $request->headers->has('Origin');

      if ($requestHasOrigin)
      {
        $origin = $request->headers->get('Origin');

        $host = $request->getSchemeAndHttpHost();

        if ($origin !== $host)
        {
          return true;
        }
      }

      return false;
    }

    /**
     * Dynamic resolution of allowed origin since we can't
     * pass multiple domains to the header. The appropriate
     * domain is set in the Access-Control-Allow-Origin header
     * only if it is present in the whitelist.
     *
     * @param  \Illuminate\Http\Request  $request
     */
    private function resolveAllowedOrigin($request)
    {
      $allowedOrigin = static::$allowedOrigin;

      // If origin is in our $allowedOriginsWhitelist
      // then we send that in Access-Control-Allow-Origin

      $origin = $request->headers->get('Origin');

      if (in_array($origin, static::$allowedOriginsWhitelist))
      {
        $allowedOrigin = $origin;
      }

      return $allowedOrigin;
    }

    /**
     * Take the incoming client request headers
     * and return. Will be used to pass in Access-Control-Allow-Headers
     *
     * @param  \Illuminate\Http\Request  $request
     */
    private function resolveAllowedHeaders($request)
    {
      $allowedHeaders = $request->headers->get('Access-Control-Request-Headers');

      return $allowedHeaders;
    }
}

我也写了一篇关于这个的博客文章


太棒了,我读了你的博客文章,它非常有效。谢谢! - darksoulsong
@Rishabh,我刚刚在查关于一些CORS相关的Laravel问题,几乎每个答案都是一样的,但这个答案确实非常好。 - Arun P

11

对于我来说,我把这些代码放在public\index.php文件中。对于所有的CRUD操作,它都能正常工作。

header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, PUT, POST, DELETE, OPTIONS, post, get');
header("Access-Control-Max-Age", "3600");
header('Access-Control-Allow-Headers: Origin, Content-Type, X-Auth-Token');
header("Access-Control-Allow-Credentials", "true");


10

barryvdh/laravel-cors 只需要在几个关键点上启用即可与 Laravel 5.1 完美配合。

  1. 将其添加为 composer 依赖项后,确保您已发布了 CORS 配置文件,并根据需要调整 CORS 标头。以下是我在 app/config/cors.php 中的设置:

<?php

return [

    'supportsCredentials' => true,
    'allowedOrigins' => ['*'],
    'allowedHeaders' => ['*'],
    'allowedMethods' => ['GET', 'POST', 'PUT',  'DELETE'],
    'exposedHeaders' => ['DAV', 'content-length', 'Allow'],
    'maxAge' => 86400,
    'hosts' => [],
];
  • 接下来,还有一个在文档中没有提到的步骤,你需要在应用内核中添加CORS处理程序'Barryvdh\Cors\HandleCors'。我喜欢将它放在全局中间件堆栈中使用。就像这样:

  • /**
     * The application's global HTTP middleware stack.
     *
     * @var array
     */
    protected $middleware = [
        'Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode',
        'Illuminate\Cookie\Middleware\EncryptCookies',
        'Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse',
        'Illuminate\Session\Middleware\StartSession',
        'Illuminate\View\Middleware\ShareErrorsFromSession',
    
        'Barryvdh\Cors\HandleCors',
    
    ];
    

    但是你可以将它用作路由中间件并放置在特定的路由上。

    这应该使该包与L5.1兼容。


    我一直在寻找每个配置文件元素的详细信息,特别是"exposedHeaders"和"supportsCredentials",但不幸的是,我还没有成功,你介意给一些详细信息或者提供一个参考吗?非常感谢! - Bahman.A

    2

    Laravel 8

    创建一个中间件

    <?php
    
    namespace App\Http\Middleware;
    
    use Closure;
    use Illuminate\Http\Request;
    
    class CorsMiddleware
    {
        public function handle(Request $request, Closure $next)
        {
            return $next($request)
                ->header('Access-Control-Allow-Origin', config('cors.allowed_origins')) 
                ->header('Access-Control-Allow-Methods', config('cors.allowed_methods'))
                ->header('Access-Control-Allow-Headers',config('cors.allowed_headers'));
        }
    }
    

    config/cors.php

    return [
        'paths' => [
            'api/*', 
            'admin/api/*', 
            'sanctum/csrf-cookie'
        ],
        'allowed_methods' => [ //'GET, POST, PUT, PATCH, DELETE, OPTIONS'
            'GET', 
            'POST', 
            'PUT', 
            'PATCH', 
            'DELETE', 
            'OPTIONS'
        ],
        'allowed_origins' => ['*'],
        'allowed_origins_patterns' => [],
        'allowed_headers' => [//  'Content-Type, Authorization, Accept'
            'Content-Type', 
            'Authorization', 
            'Accept'
        ],
        'exposed_headers' => [],
        'max_age' => 0,
        'supports_credentials' => true,
    ];
    
    

    kernel.php for http

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

    2
    如果你的路由没有通过函数闭包或控制器操作返回响应,那么它将无法工作。

    它不起作用了

    控制器操作

    Route::post('login','AuthController@login');
    
    class AuthController extends Controller {
    
         ...
    
         public function login() {
              dd(['key' => 'value']);
              //OR
              die(['key' => 'value']);
              //OR
              print_r(['key' => 'value');
              exit();
         }
    
         ...
    
    }
    

    它可用!

    控制器操作

    Route::post('login','AuthController@login');
    
    class AuthController extends Controller {
    
         ...
    
         public function login() {
              return response()->json(['key' => 'value'], 200);
              // OR
              return ['key' => 'value'];
              // OR
              $data = ['key' => 'value'];
              return $data;
         }
    
         ...
    
    }
    

    测试CORS

    Chrome浏览器 -> 开发者工具 -> 网络选项卡

    enter image description here

    如果有任何问题,那么您的响应头将不会显示在此处。


    1

    https://github.com/fruitcake/laravel-cors

    请使用这个库。按照此存储库中提到的说明操作。
    请记住,不要在CORS URL中使用 dd() 或 die() ,因为这个库将无法工作。始终使用带有CORS URL的返回。
    谢谢

    0

    只需将其用作中间件即可

    <?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)
        {
            $response = $next($request);
            $response->header('Access-Control-Allow-Origin', '*');
            $response->header('Access-Control-Allow-Methods', '*');
    
            return $response;
        }
    }
    

    并在您的内核文件中注册中间件,路径为app/Http/Kernel.php,选择您喜欢的组,一切都会很好。


    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接