Laravel 10. Как решить проблему с CORS при получении фотографий?

Ссылка скопирована
1 ответ

Laravel работает как API сервис для фронта, фронт на react.
Обычные API ссылки вызываются без проблем: https://api.dev.site.ru/api/products
Фотки находятся по адресу https://api.dev.site.ru/images/tickets/cat.jpg

Запрос идет с адреса: https://develop.app.site.ru/

Доступ к фотке закрыт по Bearer token.

Если я локально тестирую где у меня и бек и фронт на одном домене test.ru, то там все хорошо. Фотка отображается у нее код ответа 200.

Если я в postman открываю фотку с удаленного сайта https://api.dev.site.ru/images/tickets/cat.jpg, то она открывается но у него код ответа почему то 404, у локальной фотки код ответа 200. И локально и удалено один и тот же сайт с одинаковыми настройками.

Убрав проверку авторизации с фотки, она открылась на сайте, но ошибка CORS осталась и по прямой ссылке в браузере она открывается с кодом 404

Файл config/cors.php:

<?php  return [      /*     |--------------------------------------------------------------------------     | Cross-Origin Resource Sharing (CORS) Configuration     |--------------------------------------------------------------------------     |     | Here you may configure your settings for cross-origin resource sharing     | or "CORS". This determines what cross-origin operations may execute     | in web browsers. You are free to adjust these settings as needed.     |     | To learn more: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS     |     */      'paths' => ['api/*', 'sanctum/csrf-cookie', 'images/*'],     'allowed_methods' => ['*'],     'allowed_origins' => ['*'],     'allowed_origins_patterns' => [],     'allowed_headers' => ['*'],     'exposed_headers' => [],     'max_age' => 0,     'supports_credentials' => false, ];

<?php return [ /* |-------------------------------------------------------------------------- | Cross-Origin Resource Sharing (CORS) Configuration |-------------------------------------------------------------------------- | | Here you may configure your settings for cross-origin resource sharing | or "CORS". This determines what cross-origin operations may execute | in web browsers. You are free to adjust these settings as needed. | | To learn more: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS | */ 'paths' => ['api/*', 'sanctum/csrf-cookie', 'images/*'], 'allowed_methods' => ['*'], 'allowed_origins' => ['*'], 'allowed_origins_patterns' => [], 'allowed_headers' => ['*'], 'exposed_headers' => [], 'max_age' => 0, 'supports_credentials' => false, ];

Файл app/Provited/RouteServiceProvider.php:

<?php  namespace AppProviders;  use IlluminateCacheRateLimitingLimit; use IlluminateFoundationSupportProvidersRouteServiceProvider as ServiceProvider; use IlluminateHttpRequest; use IlluminateSupportFacadesRateLimiter; use IlluminateSupportFacadesRoute;  class RouteServiceProvider extends ServiceProvider {     /**      * The path to the "home" route for your application.      *      * This is used by Laravel authentication to redirect users after login.      *      * @var string      */     public const HOME = '/home';      /**      * The controller namespace for the application.      *      * When present, controller route declarations will automatically be prefixed with this namespace.      *      * @var string|null      */     // protected $namespace = 'App\Http\Controllers';      /**      * Define your route model bindings, pattern filters, etc.      *      * @return void      */     public function boot(): void     {         $this->configureRateLimiting();          $this->routes(function () {             Route::prefix('api')                 ->middleware('api')                 ->namespace($this->namespace)                 ->group(base_path('routes/api.php'));              Route::prefix('images')                 ->middleware('cors')                 ->namespace($this->namespace)                 ->group(base_path('routes/images.php'));              Route::middleware('web')                 ->namespace($this->namespace)                 ->group(base_path('routes/web.php'));         });     }      /**      * Configure the rate limiters for the application.      *      * @return void      */     protected function configureRateLimiting(): void     {         RateLimiter::for('api', function (Request $request) {             return Limit::perMinute(60)->by(optional($request->user())->id ?: $request->ip());         });         RateLimiter::for('images', function (Request $request) {             return Limit::perMinute(60)->by(optional($request->user())->id ?: $request->ip());         });     } }

<?php namespace AppProviders; use IlluminateCacheRateLimitingLimit; use IlluminateFoundationSupportProvidersRouteServiceProvider as ServiceProvider; use IlluminateHttpRequest; use IlluminateSupportFacadesRateLimiter; use IlluminateSupportFacadesRoute; class RouteServiceProvider extends ServiceProvider { /** * The path to the "home" route for your application. * * This is used by Laravel authentication to redirect users after login. * * @var string */ public const HOME = '/home'; /** * The controller namespace for the application. * * When present, controller route declarations will automatically be prefixed with this namespace. * * @var string|null */ // protected $namespace = 'App\Http\Controllers'; /** * Define your route model bindings, pattern filters, etc. * * @return void */ public function boot(): void { $this->configureRateLimiting(); $this->routes(function () { Route::prefix('api') ->middleware('api') ->namespace($this->namespace) ->group(base_path('routes/api.php')); Route::prefix('images') ->middleware('cors') ->namespace($this->namespace) ->group(base_path('routes/images.php')); Route::middleware('web') ->namespace($this->namespace) ->group(base_path('routes/web.php')); }); } /** * Configure the rate limiters for the application. * * @return void */ protected function configureRateLimiting(): void { RateLimiter::for('api', function (Request $request) { return Limit::perMinute(60)->by(optional($request->user())->id ?: $request->ip()); }); RateLimiter::for('images', function (Request $request) { return Limit::perMinute(60)->by(optional($request->user())->id ?: $request->ip()); }); } }

Файл config/auth.php:

<?php  return [      /*     |--------------------------------------------------------------------------     | Authentication Defaults     |--------------------------------------------------------------------------     |     | This option controls the default authentication "guard" and password     | reset options for your application. You may change these defaults     | as required, but they're a perfect start for most applications.     |     */      'defaults' => [         'guard' => 'web',         'passwords' => 'users',     ],      /*     |--------------------------------------------------------------------------     | Authentication Guards     |--------------------------------------------------------------------------     |     | Next, you may define every authentication guard for your application.     | Of course, a great default configuration has been defined for you     | here which uses session storage and the Eloquent user provider.     |     | All authentication drivers have a user provider. This defines how the     | users are actually retrieved out of your database or other storage     | mechanisms used by this application to persist your user's data.     |     | Supported: "session"     |     */      'guards' => [         'web' => [             'driver' => 'session',             'provider' => 'users',         ],         'images' => [             'driver' => 'passport',             'provider' => 'users',         ],         'api' => [             'driver' => 'passport',             'provider' => 'users',         ]     ],      /*     |--------------------------------------------------------------------------     | User Providers     |--------------------------------------------------------------------------     |     | All authentication drivers have a user provider. This defines how the     | users are actually retrieved out of your database or other storage     | mechanisms used by this application to persist your user's data.     |     | If you have multiple user tables or models you may configure multiple     | sources which represent each model / table. These sources may then     | be assigned to any extra authentication guards you have defined.     |     | Supported: "database", "eloquent"     |     */      'providers' => [         'users' => [             'driver' => 'eloquent',             'model' => AppModelsUser::class,         ],          // 'users' => [         //     'driver' => 'database',         //     'table' => 'users',         // ],     ],      /*     |--------------------------------------------------------------------------     | Resetting Passwords     |--------------------------------------------------------------------------     |     | You may specify multiple password reset configurations if you have more     | than one user table or model in the application and you want to have     | separate password reset settings based on the specific user types.     |     | The expire time is the number of minutes that each reset token will be     | considered valid. This security feature keeps tokens short-lived so     | they have less time to be guessed. You may change this as needed.     |     */      'passwords' => [         'users' => [             'provider' => 'users',             'table' => 'password_resets',             'expire' => 60,             'throttle' => 60,         ],     ],      /*     |--------------------------------------------------------------------------     | Password Confirmation Timeout     |--------------------------------------------------------------------------     |     | Here you may define the amount of seconds before a password confirmation     | times out and the user is prompted to re-enter their password via the     | confirmation screen. By default, the timeout lasts for three hours.     |     */      'password_timeout' => 10800, ];

<?php return [ /* |-------------------------------------------------------------------------- | Authentication Defaults |-------------------------------------------------------------------------- | | This option controls the default authentication "guard" and password | reset options for your application. You may change these defaults | as required, but they're a perfect start for most applications. | */ 'defaults' => [ 'guard' => 'web', 'passwords' => 'users', ], /* |-------------------------------------------------------------------------- | Authentication Guards |-------------------------------------------------------------------------- | | Next, you may define every authentication guard for your application. | Of course, a great default configuration has been defined for you | here which uses session storage and the Eloquent user provider. | | All authentication drivers have a user provider. This defines how the | users are actually retrieved out of your database or other storage | mechanisms used by this application to persist your user's data. | | Supported: "session" | */ 'guards' => [ 'web' => [ 'driver' => 'session', 'provider' => 'users', ], 'images' => [ 'driver' => 'passport', 'provider' => 'users', ], 'api' => [ 'driver' => 'passport', 'provider' => 'users', ] ], /* |-------------------------------------------------------------------------- | User Providers |-------------------------------------------------------------------------- | | All authentication drivers have a user provider. This defines how the | users are actually retrieved out of your database or other storage | mechanisms used by this application to persist your user's data. | | If you have multiple user tables or models you may configure multiple | sources which represent each model / table. These sources may then | be assigned to any extra authentication guards you have defined. | | Supported: "database", "eloquent" | */ 'providers' => [ 'users' => [ 'driver' => 'eloquent', 'model' => AppModelsUser::class, ], // 'users' => [ // 'driver' => 'database', // 'table' => 'users', // ], ], /* |-------------------------------------------------------------------------- | Resetting Passwords |-------------------------------------------------------------------------- | | You may specify multiple password reset configurations if you have more | than one user table or model in the application and you want to have | separate password reset settings based on the specific user types. | | The expire time is the number of minutes that each reset token will be | considered valid. This security feature keeps tokens short-lived so | they have less time to be guessed. You may change this as needed. | */ 'passwords' => [ 'users' => [ 'provider' => 'users', 'table' => 'password_resets', 'expire' => 60, 'throttle' => 60, ], ], /* |-------------------------------------------------------------------------- | Password Confirmation Timeout |-------------------------------------------------------------------------- | | Here you may define the amount of seconds before a password confirmation | times out and the user is prompted to re-enter their password via the | confirmation screen. By default, the timeout lasts for three hours. | */ 'password_timeout' => 10800, ];

Файл routes/images.php:

<?php  use AppHttpControllersImageController; use IlluminateSupportFacadesRoute;  Route::middleware('auth:images')->group(function () {     Route::get('tickets/{filename}', [ImageController::class, 'showTicketImage']); });

<?php use AppHttpControllersImageController; use IlluminateSupportFacadesRoute; Route::middleware('auth:images')->group(function () { Route::get('tickets/{filename}', [ImageController::class, 'showTicketImage']); });

Файл app/Http/Controllers/ImageController.php:

<?php  namespace AppHttpControllers;  use AppModulesCommon; use InterventionImageFacadesImage; use IlluminateHttpRequest;  class ImageController extends Controller {     /**      * Получение фотки тикета      *      * @param Request $request      * @param string $fileName      * @return mixed      */     public function showTicketImage(Request $request, string $fileName): mixed     {         $path = storage_path(Common::TICKET_PATH . $fileName);          if (!file_exists($path))             return response('', 404);          return Image::make($path)->response();     } }

<?php namespace AppHttpControllers; use AppModulesCommon; use InterventionImageFacadesImage; use IlluminateHttpRequest; class ImageController extends Controller { /** * Получение фотки тикета * * @param Request $request * @param string $fileName * @return mixed */ public function showTicketImage(Request $request, string $fileName): mixed { $path = storage_path(Common::TICKET_PATH . $fileName); if (!file_exists($path)) return response('', 404); return Image::make($path)->response(); } }

Файл nginx стандартный который при установке nginx последней версии там добавляется.

Дополнительно:

1) Где текст CORS ошибки?

2) Почему в роутах /images/tickets/{filename} а в примерах https://api.dev.site.ru/images/cat.jpg?

images/tickets != images Этот урл вообще не должен обрабатываться твои контроллером (ImageController@showTicketImage).

  • это я не правильно ссылку указал, поправил. Вообщем /images/tickets/{fileName}
  • Cross-Origin Resource Sharing error: PreflightMissing Allow OriginHeader такая ошибка
  • Laravel 10. Как решить проблему с CORS при получении фотографий?

    Если в хроме в нетворк выбрать ALL то вот три строчки таких на фотку получается.

  • Убрав проверку авторизации с фотки, она открылась на сайте, но ошибка CORS осталась и по прямой ссылке в браузере она открывается с кодом 404
  • Для этого роута supports_credentials должно быть true, так как там есть Bearer token
  • Kerm, убрал только со стороны бека? А фронт по прежнему отправляет Authorization заголовок?
  • YepBro, да
  • YepBro, дык api методы они все с токенами в config/cors.php: там одни настройки для api/* и images/*
  • Kerm, ну тогда supports_credentials должно быть true в config/cors.php для этого роута.
  • YepBro, знаешь чего еще нашел, метод OPTIONS при запросе фото возвращает:
    <html>  <head> 	<title>405 Not Allowed</title> </head>  <body> 	<center> 		<h1>405 Not Allowed</h1> 	</center> 	<hr> 	<center>nginx</center> </body>  </html>

    <html> <head> <title>405 Not Allowed</title> </head> <body> <center> <h1>405 Not Allowed</h1> </center> <hr> <center>nginx</center> </body> </html>

    тогда как /api нормально работает с options

  • Kerm, Это ответ от nginx, а не от твоего бекенда. Стоит посмотреть конфиг nginx, может там картинки отдельным локейшеном обрабатываются. И еще, нет ли на диске этих картинок в public/images/tickets/* ?
  • YepBro, картинки хранятся по адресу storage/app/public/tickets-images
  • YepBro, конфиг nginx стандартный:

    Laravel 10. Как решить проблему с CORS при получении фотографий?

    Laravel 10. Как решить проблему с CORS при получении фотографий?

  • Kerm, попробуй закоментировать строку expires 5d;
  • YepBro, спасибо! дело оказалось в кеше картинок, убрал и все заработало как надо.
  • Kerm, nginx? или в laravel был свой реализован?
  • YepBro, nginx, там для картинок стояло expires 5d; конфиг выше можно посмотреть
Нужно решить такую задачу?

Опишите проблему, и специалист поможет с настройкой, исправлением ошибки или доработкой сайта. Подберём понятный план работ без лишней переписки.

Заказать помощь
Лучший ответ
1
Андрей PHP Ответ

Для решения проблемы с CORS (Cross-Origin Resource Sharing) при получении фотографий в Laravel 10, необходимо выполнить несколько шагов.

1. Установите пакет barryvdh/laravel-cors с помощью Composer. Вы можете сделать это, запустив следующую команду в корневой директории вашего проекта:

composer require barryvdh/laravel-cors

composer require barryvdh/laravel-cors

2. После установки пакета, опубликуйте его конфигурационный файл, запустив команду:

php artisan vendor:publish --provider="Barryvdh\Cors\ServiceProvider"

php artisan vendor:publish --provider="Barryvdh\Cors\ServiceProvider"

3. Теперь вам нужно настроить CORS в файле config/cors.php. Вы можете разрешить доступ к вашему приложению с определенных доменов, настроив массив allowed_origins в этом файле. Например:

'allowed_origins' => ['http://example.com', 'https://example.com'],

'allowed_origins' => ['http://example.com', 'https://example.com'],

4. Вы также можете настроить другие параметры CORS, такие как allowed_methods, allowed_headers и т.д. в файле config/cors.php.

5. Не забудьте добавить промежуточное ПО Cors в ваше приложение. Для этого откройте файл app/Http/Kernel.php и добавьте Cors в массив $middleware:

protected $middleware = [
    // другие промежуточные ПО
    \Barryvdh\Cors\HandleCors::class,
];

protected $middleware = [ // другие промежуточные ПО \Barryvdh\Cors\HandleCors::class, ];

После выполнения этих шагов, проблема с CORS при получении фотографий в Laravel 10 должна быть успешно решена. Ваши запросы к фотографиям теперь должны проходить без проблем с CORS.

Другие ответы (0)

Пока нет других ответов. Будьте первым, кто поможет автору.

Ответить на вопрос

комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Вам также может быть интересно