Laravel 10获取图片时出现CORS错误,请求协助排查
问题描述
使用Laravel 10搭建API,尝试获取public/images文件夹中的图片:
- 控制器
show方法返回图片URL:
public function show() { $imageUrl = asset('images/myimage.png'); return response()->json(['imageUrl' => $imageUrl]); }
- API路由配置:
Route::get('images', [ImageController::class, 'show']); Route::post('images', [ImageController::class, 'store']);
- Postman访问
http://127.0.0.1:8000/api/images返回正常,直接打开图片URL也能查看,但Angular 15前端请求图片时出现CORS错误:
Access to XMLHttpRequest at 'http://127.0.0.1:8000/images/myimage.png' from origin 'http://localhost:4200' 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.
- 已配置
cors.php:
<?php return [ 'paths' => ['api/*', 'images/*'], 'allowed_methods' => ['*'], 'allowed_origins' => ['*'], 'allowed_origins_patterns' => [], 'allowed_headers' => ['*'], 'exposed_headers' => [], 'max_age' => 0, 'supports_credentials' => false, ];
- 修改了
Kernel.php添加CORS中间件,无效果:
protected $middleware = [ // \App\Http\Middleware\TrustHosts::class, \App\Http\Middleware\TrustProxies::class, \Illuminate\Http\Middleware\HandleCors::class, \App\Http\Middleware\PreventRequestsDuringMaintenance::class, \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class, \App\Http\Middleware\TrimStrings::class, \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class, ]; protected $middlewareGroups = [ 'web' => [ \App\Http\Middleware\EncryptCookies::class, \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class, \Illuminate\Session\Middleware\StartSession::class, \Illuminate\View\Middleware\ShareErrorsFromSession::class, \App\Http\Middleware\VerifyCsrfToken::class, \Illuminate\Routing\Middleware\SubstituteBindings::class, ], 'api' => [ // \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class, \Illuminate\Routing\Middleware\ThrottleRequests::class.':api', \Illuminate\Routing\Middleware\SubstituteBindings::class, \Illuminate\Http\Middleware\HandleCors::class ], 'images' => [ \Illuminate\Http\Middleware\HandleCors::class ] ]; protected $middlewareAliases = [ 'auth' => \App\Http\Middleware\Authenticate::class, 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class, 'auth.session' => \Illuminate\Session\Middleware\AuthenticateSession::class, 'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class, 'can' => \Illuminate\Auth\Middleware\Authorize::class, 'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class, 'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class, 'signed' => \App\Http\Middleware\ValidateSignature::class, 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class, 'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class, ];
- Angular配置了代理文件:
{ "/api/*": { "target": "http://localhost:8000", "secure": false, "logLevel": "debug", "changeOrigin": true }, "/images/*": { "target": "http://localhost:8000", "secure": false, "logLevel": "debug" } }
- Angular请求图片的方法:
getImage(): Observable<Blob> { const headers = new HttpHeaders({ 'Content-Type': 'image/png' }); return this.http.get('http://127.0.0.1:8000/images/myimage.png', { headers, responseType: 'arraybuffer' }).pipe( map((response: ArrayBuffer) => { return new Blob([response], { type: 'image/png' }); }) ); }
解决方案
1. 核心原因
Laravel的HandleCors中间件仅处理通过Laravel路由匹配的请求,而public/images下的静态文件是直接由服务器(如Apache/Nginx)或Laravel底层静态资源处理器返回的,不会触发CORS中间件,因此缺少Access-Control-Allow-Origin响应头。
2. 解决方法一:通过Laravel路由返回图片(推荐)
修改路由配置,将静态图片请求交由控制器处理,手动添加CORS头:
- 在
routes/api.php中添加命名路由:
Route::get('images/{filename}', [ImageController::class, 'serveImage'])->name('images.serve');
- 在
ImageController中新增处理方法:
public function serveImage($filename) { $imagePath = public_path("images/{$filename}"); if (!file_exists($imagePath)) { abort(404, 'Image not found'); } // 返回图片并添加CORS头 return response()->file($imagePath)->header('Access-Control-Allow-Origin', '*'); }
- 修改原
show方法返回路由生成的URL:
public function show() { $imageUrl = route('images.serve', ['filename' => 'myimage.png']); return response()->json(['imageUrl' => $imageUrl]); }
3. 解决方法二:正确使用Angular代理
代理配置已正确,但请求未走代理,需修改为相对路径并指定代理启动:
- 修改Angular的
getImage方法:
getImage(): Observable<Blob> { const headers = new HttpHeaders({ 'Content-Type': 'image/png' }); // 使用相对路径,让代理接管请求 return this.http.get('/images/myimage.png', { headers, responseType: 'arraybuffer' }).pipe( map((response: ArrayBuffer) => { return new Blob([response], { type: 'image/png' }); }) ); }
- 启动Angular时必须指定代理配置文件:
ng serve --proxy-config proxy.conf.json
4. 额外注意事项
- 统一源地址:Laravel的
asset函数使用127.0.0.1,Angular代理目标是localhost,浏览器会将二者视为不同源,建议统一为同一地址。 - 无需单独创建
images中间件组:全局中间件中已添加HandleCors,足够处理所有路由请求,静态资源问题需通过上述两种方法解决。
内容的提问来源于stack exchange,提问作者malany_tr
相关产品推荐
相关产品推荐

