PHP에서 브라우저 캐시 문제 해결하기

프리터코더·2025년 6월 2일
0

php 문제 해결

목록 보기
56/79

웹 개발 시 브라우저 캐시로 인해 최신 데이터가 표시되지 않거나, 반대로 캐시되지 말아야 할 민감한 데이터가 캐시되는 문제가 발생할 수 있습니다. 상황에 따른 적절한 캐시 제어 방법을 알아보겠습니다.

1. 캐시 완전 비활성화

<?php
// 모든 캐시 비활성화
header('Cache-Control: no-cache, no-store, must-revalidate');
header('Pragma: no-cache');
header('Expires: 0');

// 민감한 데이터 출력
echo json_encode(['user_data' => $sensitive_data]);
?>

2. 정적 파일 캐시 설정

<?php
// 1년간 캐시 (정적 리소스용)
$expire_time = 60 * 60 * 24 * 365; // 1년

header('Cache-Control: public, max-age=' . $expire_time);
header('Expires: ' . gmdate('D, d M Y H:i:s', time() + $expire_time) . ' GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s', filemtime(__FILE__)) . ' GMT');

// CSS, JS, 이미지 파일 등 출력
readfile('style.css');
?>

3. ETag를 이용한 조건부 캐시

<?php
$data = ['timestamp' => time(), 'content' => 'some data'];
$etag = md5(serialize($data));

header('ETag: "' . $etag . '"');

// 클라이언트의 ETag와 비교
if (isset($_SERVER['HTTP_IF_NONE_MATCH']) && $_SERVER['HTTP_IF_NONE_MATCH'] === '"' . $etag . '"') {
    header('HTTP/1.1 304 Not Modified');
    exit;
}

header('Content-Type: application/json');
echo json_encode($data);
?>

4. Last-Modified 헤더 활용

<?php
$file_path = 'data.json';
$last_modified = filemtime($file_path);

header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $last_modified) . ' GMT');

// 클라이언트의 If-Modified-Since와 비교
if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
    $client_modified = strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']);
    if ($client_modified >= $last_modified) {
        header('HTTP/1.1 304 Not Modified');
        exit;
    }
}

readfile($file_path);
?>

5. 버전 파라미터로 캐시 무효화

<?php
function getAssetUrl($file) {
    $version = filemtime($file);
    return $file . '?v=' . $version;
}

// HTML에서 사용
?>
<link rel="stylesheet" href="<?php echo getAssetUrl('css/style.css'); ?>">
<script src="<?php echo getAssetUrl('js/app.js'); ?>"></script>

6. 세션별 캐시 제어

<?php
session_start();

// 로그인한 사용자는 캐시 비활성화
if (isset($_SESSION['user_id'])) {
    header('Cache-Control: private, no-cache, no-store, must-revalidate');
    header('Pragma: no-cache');
} else {
    // 비로그인 사용자는 짧은 캐시 허용
    header('Cache-Control: public, max-age=300'); // 5분
}

echo $content;
?>

7. API 응답 캐시 제어

<?php
function sendApiResponse($data, $cache_duration = 0) {
    header('Content-Type: application/json');
    
    if ($cache_duration > 0) {
        header('Cache-Control: public, max-age=' . $cache_duration);
        header('Expires: ' . gmdate('D, d M Y H:i:s', time() + $cache_duration) . ' GMT');
    } else {
        header('Cache-Control: no-cache, no-store, must-revalidate');
        header('Pragma: no-cache');
        header('Expires: 0');
    }
    
    echo json_encode($data);
}

// 사용 예시
sendApiResponse($user_data, 0); // 캐시 안함
sendApiResponse($static_data, 3600); // 1시간 캐시
?>

8. 조건부 캐시 클래스

<?php
class CacheControl {
    public static function noCache() {
        header('Cache-Control: no-cache, no-store, must-revalidate');
        header('Pragma: no-cache');
        header('Expires: 0');
    }
    
    public static function longCache($seconds = 86400) {
        header('Cache-Control: public, max-age=' . $seconds);
        header('Expires: ' . gmdate('D, d M Y H:i:s', time() + $seconds) . ' GMT');
    }
    
    public static function privateCache($seconds = 300) {
        header('Cache-Control: private, max-age=' . $seconds);
    }
}

// 사용 예시
CacheControl::noCache(); // 관리자 페이지
CacheControl::longCache(604800); // 정적 리소스 (1주일)
CacheControl::privateCache(600); // 사용자별 데이터 (10분)
?>

핵심 포인트

  • 민감한 데이터는 반드시 no-cache, no-store 설정
  • 정적 리소스는 긴 캐시 시간과 버전 파라미터 활용
  • ETag와 Last-Modified로 효율적인 캐시 검증
  • API 응답은 데이터 성격에 따라 캐시 정책 차별화
  • 개발 환경에서는 캐시 비활성화로 테스트 용이성 확보
profile
일용직 개발자. freetercoder@gmail.com

0개의 댓글