From 168b8ee48eb1b64dd47600a9db6cf69dcda36b75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B6=8C=ED=98=81=EC=84=B1?= Date: Fri, 20 Mar 2026 00:36:52 +0900 Subject: [PATCH] =?UTF-8?q?refactor:=20FileViewController=EB=A5=BC=20presi?= =?UTF-8?q?gned=20URL=20redirect=20=EB=B0=A9=EC=8B=9D=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EC=A0=84=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 바이너리 스트리밍 프록시 → R2 presigned URL 302 redirect - 하드코딩 X-TENANT-ID: 287 → session 기반으로 수정 - 하드코딩 API 키 폴백 제거 - presigned URL 5분 캐시 적용 Co-Authored-By: Claude Opus 4.6 (1M context) --- app/Http/Controllers/FileViewController.php | 50 ++++++++++++--------- 1 file changed, 29 insertions(+), 21 deletions(-) diff --git a/app/Http/Controllers/FileViewController.php b/app/Http/Controllers/FileViewController.php index 5730ada5..1ce6fc73 100644 --- a/app/Http/Controllers/FileViewController.php +++ b/app/Http/Controllers/FileViewController.php @@ -2,40 +2,48 @@ namespace App\Http\Controllers; +use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\Http; /** - * R2 파일 프록시 (MNG 세션 인증으로 API 파일 스트리밍) + * R2 파일 Presigned URL 리다이렉트 * - * MNG는 Blade(서버사이드)이므로 API의 /files/{id}/view를 직접 호출 시 - * sanctum 인증 문제가 발생. MNG 세션 인증으로 API를 프록시하여 파일 스트리밍. + * API에서 R2 presigned URL을 발급받아 브라우저를 직접 R2로 리다이렉트. + * presigned URL은 5분간 캐시하여 동일 이미지 반복 요청 시 API 호출 최소화. */ class FileViewController extends Controller { public function show(int $id) { - $baseUrl = config('services.api.base_url', 'https://api.sam.kr'); - $apiKey = config('services.api.key') ?: '42Jfwc6EaRQ04GNRmLR5kzJp5UudSOzGGqjmdk1a'; - $token = session('api_access_token', ''); + $cacheKey = "file_presigned_url:{$id}"; - $response = Http::baseUrl($baseUrl) - ->withoutVerifying() - ->withHeaders([ - 'X-API-KEY' => $apiKey, - 'X-TENANT-ID' => 287, // TODO: session('selected_tenant_id', 1) 로 복원 - ]) - ->withToken($token) - ->timeout(15) - ->get("/api/v1/files/{$id}/view"); + $url = Cache::remember($cacheKey, now()->addMinutes(5), function () use ($id) { + $baseUrl = config('services.api.base_url', 'https://api.sam.kr'); + $apiKey = config('services.api.key'); + $token = session('api_access_token', ''); - if (! $response->successful()) { + $response = Http::baseUrl($baseUrl) + ->withoutVerifying() + ->withHeaders([ + 'X-API-KEY' => $apiKey, + 'X-TENANT-ID' => session('selected_tenant_id', 1), + ]) + ->withToken($token) + ->timeout(10) + ->get("/api/v1/files/{$id}/presigned-url"); + + if (! $response->successful()) { + return null; + } + + return $response->json('data.url'); + }); + + if (! $url) { + Cache::forget($cacheKey); abort(404); } - return response($response->body(), 200, [ - 'Content-Type' => $response->header('Content-Type', 'image/png'), - 'Content-Disposition' => 'inline', - 'Cache-Control' => 'private, max-age=3600', - ]); + return redirect($url); } }