112 lines
3.5 KiB
PHP
112 lines
3.5 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
use Illuminate\Support\Facades\Cache;
|
|
use Illuminate\Support\Facades\Http;
|
|
|
|
/**
|
|
* R2 파일 Presigned URL 리다이렉트
|
|
*
|
|
* API에서 R2 presigned URL을 발급받아 브라우저를 직접 R2로 리다이렉트.
|
|
* presigned URL은 5분간 캐시하여 동일 이미지 반복 요청 시 API 호출 최소화.
|
|
*/
|
|
class FileViewController extends Controller
|
|
{
|
|
public function show(int $id)
|
|
{
|
|
$cacheKey = "file_presigned_url:{$id}";
|
|
|
|
$url = Cache::remember($cacheKey, now()->addMinutes(5), function () use ($id) {
|
|
$baseUrl = config('services.api.base_url', 'https://api.sam.kr');
|
|
$internalUrl = config('services.api.internal_url');
|
|
$apiKey = config('services.api.key');
|
|
$token = session('api_access_token', '');
|
|
|
|
$headers = [
|
|
'X-API-KEY' => $apiKey,
|
|
'X-TENANT-ID' => session('selected_tenant_id', 1),
|
|
];
|
|
|
|
if ($internalUrl) {
|
|
$headers['Host'] = parse_url($baseUrl, PHP_URL_HOST) ?: 'api.sam.kr';
|
|
$baseUrl = $internalUrl;
|
|
}
|
|
|
|
$response = Http::baseUrl($baseUrl)
|
|
->withoutVerifying()
|
|
->withHeaders($headers)
|
|
->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 redirect($url);
|
|
}
|
|
|
|
/**
|
|
* 이미지 프록시 (Canvas 편집기용)
|
|
*
|
|
* R2에서 이미지를 서버 사이드로 다운로드하여 같은 도메인에서 스트리밍.
|
|
* crossOrigin 요청 없이 Canvas에서 taint 없이 사용 가능.
|
|
*/
|
|
public function proxy(int $id)
|
|
{
|
|
$cacheKey = "file_presigned_url:{$id}";
|
|
|
|
$url = Cache::remember($cacheKey, now()->addMinutes(5), function () use ($id) {
|
|
$baseUrl = config('services.api.base_url', 'https://api.sam.kr');
|
|
$internalUrl = config('services.api.internal_url');
|
|
$apiKey = config('services.api.key');
|
|
$token = session('api_access_token', '');
|
|
|
|
$headers = [
|
|
'X-API-KEY' => $apiKey,
|
|
'X-TENANT-ID' => session('selected_tenant_id', 1),
|
|
];
|
|
|
|
if ($internalUrl) {
|
|
$headers['Host'] = parse_url($baseUrl, PHP_URL_HOST) ?: 'api.sam.kr';
|
|
$baseUrl = $internalUrl;
|
|
}
|
|
|
|
$response = Http::baseUrl($baseUrl)
|
|
->withoutVerifying()
|
|
->withHeaders($headers)
|
|
->withToken($token)
|
|
->timeout(10)
|
|
->get("/api/v1/files/{$id}/presigned-url");
|
|
|
|
return $response->successful() ? $response->json('data.url') : null;
|
|
});
|
|
|
|
if (! $url) {
|
|
Cache::forget($cacheKey);
|
|
abort(404);
|
|
}
|
|
|
|
$imageResponse = Http::withoutVerifying()->timeout(15)->get($url);
|
|
|
|
if (! $imageResponse->successful()) {
|
|
abort(404);
|
|
}
|
|
|
|
$contentType = $imageResponse->header('Content-Type') ?: 'image/png';
|
|
|
|
return response($imageResponse->body(), 200)
|
|
->header('Content-Type', $contentType)
|
|
->header('Cache-Control', 'public, max-age=300');
|
|
}
|
|
}
|