API 관련 수정

This commit is contained in:
2025-12-19 15:41:37 +09:00
parent 5b83c30327
commit 465a82093e
7 changed files with 131 additions and 26 deletions

4
.env
View File

@@ -12,11 +12,13 @@
#--------------------------------------------------------------------
# ENVIRONMENT
#--------------------------------------------------------------------
APP_SERVER_NAME = "TEST-SERVER-01"
CI_ENVIRONMENT = development
# CI_ENVIRONMENT = production
#--------------------------------------------------------------------
# APP
#--------------------------------------------------------------------
app.baseURL = 'http://test2.admin.confirms.co.kr/'
app.baseURL = 'http://test2-admin.confirms.co.kr/'
# If you have trouble with `.`, you could also use `_`.
# app_baseURL = ''
# app.forceGlobalSecureRequests = false

View File

@@ -29,7 +29,7 @@ class NaverWorker extends BaseCommand
while (true) {
// 메인 큐 및 재시도 큐에서 데이터 꺼내기 (Blocking Pop, 5초 타임아웃)
// LIFO (lPush/brPop) 사용 시: ['naver:queue:retry', 'naver:queue']
$item = $redis->brPop(['naver:queue'], 5);
$item = $redis->brPop(['naver:worker_queue'], 5);
if ($item) {
$payload = json_decode($item[1], true);

View File

@@ -35,6 +35,7 @@ class Filters extends BaseFilters
'pagecache' => PageCache::class,
'performance' => PerformanceMetrics::class,
'auth' => \App\Filters\AuthCheck::class,
'jsInjector' => \App\Filters\JavascriptInjector::class,
];
/**
@@ -84,13 +85,15 @@ class Filters extends BaseFilters
'index.php/login/*', // /index.php/login/*
'register', // 회원가입 등
'register/*',
'api/*', // 필요하면 API는 예외
'kiso/*', // 필요하면 API는 예외
],
],
],
'after' => [
// 'honeypot',
// 'secureheaders',
'jsInjector', // 모든 페이지 응답 후에 실행
'toolbar',
],
];

View File

@@ -16,10 +16,10 @@ class KisoController extends BaseController
public function vrfcReq()
{
// 1. 요청 방식에 따라 데이터 파싱
if ($this->request->getMethod() === 'post') {
if ( $this->request->is('post') ) {
// POST 방식: JSON Body에서 데이터 가져오기
$data = $this->request->getJSON(true);
} elseif ($this->request->getMethod() === 'get') {
} else if ( $this->request->is('get') ) {
// GET 방식: Query Parameter에서 데이터 가져오기
$data = $this->request->getGet();
} else {
@@ -29,7 +29,7 @@ class KisoController extends BaseController
}
// 2. 필수 항목 검증
$requiredKeys = ['articleNumbr', 'reqeustType', 'requestDatetime'];
$requiredKeys = ['articleNumber', 'requestType', 'requestDatetime'];
foreach ($requiredKeys as $key) {
// 파싱된 데이터($data) 내에 키가 없거나 값이 비어있는지 확인
@@ -43,32 +43,30 @@ class KisoController extends BaseController
}
// 3. Redis 연결 및 예외 처리
// 3. Redis 연결 및 직접 푸시
try {
// CI4 Cache Service 인스턴스를 가져옴. 기본 핸들러가 Redis여야 함.
// (또는 Services::cache('redis')를 사용해 RedisHandler를 명시적으로 요청)
$redis = \Config\Services::cache();
$redis = new \Redis();
// Docker 환경이므로 host를 'redis'로 설정
$success = $redis->connect('redis', 6379);
// Redis 핸들러가 맞는지 확인 (선택 사항)
if (!($redis->getHandler() instanceof RedisHandler)) {
throw new \Exception('Cache handler is not Redis. Check Config/Cache.php $handler setting.');
if (!$success) {
throw new \Exception('Redis connection failed');
}
// 요청에 재시도 횟수 초기화
$redis->select(10); // 10번 DB 선택
// 데이터 준비
$data['retry_count'] = 0;
// RedisHandler의 getClient()를 사용하여 원본 \Redis 객체를 가져옵니다.
// 주의: 모든 RedisHandler가 getClient()를 제공하는 것은 아니지만, CI4 내장 RedisHandler는 제공합니다.
$client = $redis->getHandler()->getClient();
// 큐에 push
$client->lPush('naver:queue', json_encode($data));
// 리스트에 데이터 삽입 (이 명령어가 실행되어야 monitor에 LPUSH가 뜹니다)
$redis->lPush('naver:queue', json_encode($data));
} catch (\Exception $e) {
log_message('error', 'Redis connection failed: ' . $e->getMessage());
return $this->response->setStatusCode(Response::HTTP_INTERNAL_SERVER_ERROR)
->setJSON([
'resultCode' => 'E999',
'resultMessage' => 'Internal server error (Queue system unavailable)'
]);
log_message('error', 'Redis Push Error: ' . $e->getMessage());
return $this->response->setStatusCode(500)->setJSON([
'resultCode' => 'E999',
'resultMessage' => 'Redis Connection Error'
]);
}
// 4. 성공 응답
@@ -76,7 +74,7 @@ class KisoController extends BaseController
->setJSON([
'resultCode' => 'S000',
'resultMessage' => 'Request successfully queued for processing',
'articleNumbr' => $data['articleNumbr']
'articleNumber' => $data['articleNumber']
]);
}
}

View File

@@ -0,0 +1,39 @@
<?php
namespace App\Filters;
use CodeIgniter\Filters\FilterInterface;
use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\HTTP\ResponseInterface;
class JavascriptInjector implements FilterInterface
{
public function before(RequestInterface $request, $arguments = null)
{
// 실행 전 로직 불필요
}
public function after(RequestInterface $request, ResponseInterface $response, $arguments = null)
{
// HTML 응답일 때만 실행
if (strpos($response->getHeaderLine('Content-Type'), 'text/html') === false) return;
// .env에서 서버 이름 가져오기 (없으면 'Unknown' 또는 컨테이너ID)
$serverAlias = env('APP_SERVER_NAME') ?? gethostname();
$envMode = ENVIRONMENT;
$scriptTag = "
<script>
var SERVER_INFO = {
alias: '{$serverAlias}',
env: '{$envMode}'
};
</script>
<script src='/common/js/de.js'></script>";
$body = $response->getBody();
if (strpos($body, '</body>') !== false) {
$response->setBody(str_replace('</body>', $scriptTag . '</body>', $body));
}
}
}

View File

@@ -35,3 +35,23 @@
</div>
</div>
</div>
<?php
// CI4의 환경 변수(env)를 체크하여 스타일 결정
$is_local = (ENVIRONMENT === 'development');
$status_color = $is_local ? '#ffc107' : '#007bff'; // 로컬은 노란색, 서버는 파란색
?>
<div class="app-wrapper-footer" style="border-top: 5px solid <?= $status_color ?>;">
<div class="app-footer">
<div class="app-footer__inner">
<div class="app-footer-left">
<strong>Current Mode:</strong> <?= strtoupper(ENVIRONMENT) ?>
</div>
<div class="app-footer-right">
<small class="text-muted">IP: <?= $_SERVER['SERVER_ADDR'] ?></small>
</div>
</div>
</div>
</div>

43
public/common/js/de.js Normal file
View File

@@ -0,0 +1,43 @@
(function() {
// 1. 환경 데이터 가져오기 (없으면 기본값 production)
const info = window.SERVER_INFO || { alias: 'UNKNOWN', env: 'production' };
// 2. 운영 환경이면 실행 중단 (표시 안 함)
if (info.env === 'production') {
return;
}
// 3. 테스트/로컬 환경일 때 스타일 설정 (강렬한 빨간색)
const bgColor = '#dc3545'; // 경고 의미의 빨간색
const textColor = '#ffffff';
const borderColor = '#a71d2a'; // 더 어두운 빨간색 테두리
// 4. 상태바 생성 및 스타일 적용
const statusDiv = document.createElement('div');
Object.assign(statusDiv.style, {
position: 'fixed',
bottom: '0',
left: '0',
width: '100%',
height: '32px',
backgroundColor: bgColor,
color: textColor,
textAlign: 'center',
fontSize: '14px',
lineHeight: '32px',
fontWeight: '900',
zIndex: '2147483647', // 최상단 레이어 보장
opacity: '1',
pointerEvents: 'none', // 클릭 방해 금지
boxShadow: '0 -4px 15px rgba(0,0,0,0.4)',
borderTop: `3px solid ${borderColor}`,
letterSpacing: '0.5px',
fontFamily: 'system-ui, -apple-system, sans-serif'
});
// 5. 출력 문구 (서버 이름 강조)
statusDiv.innerHTML = `⚠️ [TEST SERVER] NAME: ${info.alias} | HOST: ${window.location.hostname} ⚠️`;
// 6. 문서에 추가
document.body.appendChild(statusDiv);
})();