Files
sam-docs/changes/20260321_bending_api_internal_url_fix.md

6.3 KiB

절곡품 관리 MNG→API 연동 오류 수정

날짜: 2026-03-21 작업자: Claude Code (R&D실)

변경 개요

다른 개발자가 작성한 절곡품(Bending) 관련 컨트롤러에서 3가지 문제를 수정했다:

  1. Docker 환경에서 API_INTERNAL_URL 미적용으로 500 에러 발생
  2. API 화이트리스트 미등록으로 Bearer 토큰 없이 호출 시 401 에러 발생
  3. API 연결 실패 시 사용자에게 안내 메시지 없이 "데이터가 없습니다"만 표시

수정 1: internal_url 미적용 (MNG)

원인

MNG에서 API 호출 시 config('services.api.base_url') (https://api.sam.kr)만 사용하고, Docker 내부 통신용 internal_url 분기 처리가 없었다.

환경 사용할 URL 이유
Docker (로컬) API_INTERNAL_URL (https://nginx) 컨테이너 간 내부 통신, api.sam.kr DNS 해석 불가
서버 (개발/운영) API_BASE_URL 직접 도메인 접근 가능

수정 파일 (MNG)

파일 변경 내용
app/Http/Controllers/BendingBaseController.php api() 메서드에 internal_url + Host 헤더 분기 추가
app/Http/Controllers/BendingProductController.php api() 메서드에 internal_url + Host 헤더 분기 추가
app/Http/Controllers/FileViewController.php show() 메서드에 internal_url 분기 추가
app/Http/Controllers/DocumentTemplateController.php getPresignedUrlFromApi(), getPresignedUrlByPath() 분기 추가

수정 패턴

기존 FormulaApiService::resolveApiConnection() 패턴을 참고:

$baseUrl = config('services.api.base_url', 'https://api.sam.kr');
$internalUrl = config('services.api.internal_url');

$headers = [...];

if ($internalUrl) {
    $headers['Host'] = parse_url($baseUrl, PHP_URL_HOST) ?: 'api.sam.kr';
    $baseUrl = $internalUrl;
}

수정 2: API 화이트리스트 미등록 (API)

원인

ApiKeyMiddlewareallowWithoutAuth 화이트리스트에 절곡품 관련 라우트가 없어서, MNG에서 Bearer 토큰 없이 호출하면 401 Unauthorized가 반환되었다.

수정 파일 (API)

파일 변경 내용
app/Http/Middleware/ApiKeyMiddleware.php bending-items/*, guiderail-models/*, items/*/files, files/*/presigned-url 화이트리스트 추가
app/Http/Resources/Api/V1/BendingItemResource.php presignedUrl() 호출 시 S3 미설정 환경 에러 try-catch 처리

수정 3: API 오류 시 안내 메시지 (MNG)

원인

API 호출 실패 시 빈 데이터를 반환하여 "데이터가 없습니다"만 표시되었고, 사용자가 원인을 알 수 없었다.

수정 파일 (MNG)

파일 변경 내용
app/Http/Controllers/BendingBaseController.php API 응답 상태별 에러 메시지 분기
app/Http/Controllers/BendingProductController.php 동일 패턴 적용
resources/views/bending/base/partials/table.blade.php 에러 안내 UI 추가
resources/views/bending/products/partials/table.blade.php 에러 안내 UI 추가

안내 메시지 분기

API 응답 표시 메시지
연결 불가 (timeout/connection error) "API 서버에 연결할 수 없습니다. API 서비스 상태를 확인해 주세요."
401 Unauthorized "API 인증이 필요합니다. SAM 서비스에 로그인하여 API를 연결해 주세요."
403 Forbidden "API 접근 권한이 없습니다. 관리자에게 문의해 주세요."
기타 HTTP 에러 "API 오류가 발생했습니다. (HTTP {상태코드})"
정상 200 + 데이터 없음 "데이터가 없습니다."

수정 4: Canvas 편집기 R2 이미지 CORS 에러 (MNG)

원인

절곡품 전개도 편집기(Canvas Editor)에서 이미지를 로드할 때:

  1. fabric.Image.fromURLcrossOrigin: 'anonymous' 설정
  2. /files/{id}/view가 R2 presigned URL로 redirect
  3. R2 버킷에 CORS 허용 설정이 없어 브라우저가 차단
  4. Canvas가 "tainted" 상태가 되어 toDataURL() 실패

수정 파일 (MNG)

파일 변경 내용
app/Http/Controllers/FileViewController.php proxy() 메서드 추가 — R2 이미지를 서버에서 다운로드 후 같은 도메인으로 스트리밍
routes/web.php /files/{id}/proxy 라우트 추가
public/js/canvas-editor.js fabric.Image.fromURLcrossOrigin: 'anonymous' 옵션 추가
resources/views/bending/base/form.blade.php <img> 태그에 data-proxy-url 속성 추가, Canvas 편집기에서 프록시 URL 사용
resources/views/bending/products/form.blade.php 동일 패턴 적용

동작 원리

  • 일반 <img> 표시: /files/{id}/view → R2 redirect (CORS 불필요, 빠름)
  • Canvas 편집기: /files/{id}/proxy → MNG 서버가 R2에서 다운로드 후 스트리밍 (같은 도메인, CORS 무관)

로컬 .env 변경

API .env에 Cloudflare R2 접속 정보 추가 (개발서버와 동일):

R2_ACCESS_KEY_ID=cecd4d4c...
R2_SECRET_ACCESS_KEY=f20136ec...
R2_BUCKET=sam
R2_ENDPOINT=https://caf8dcb2c4ea443018ee5e7a7421db0e.r2.cloudflarestorage.com
R2_REGION=auto

신규 API 호출 코드 작성 시 필수 규칙

MNG에서 API를 호출하는 코드를 새로 작성할 때:

필수  config('services.api.internal_url') 확인 후 분기 처리
필수  internal_url 사용 시 Host 헤더에 base_url의 도메인 전달
필수  MNG에서 Bearer 없이 호출하려면 API 화이트리스트에 라우트 추가
권장  FormulaApiService::resolveApiConnection() 참조
권장  API 실패 시 사용자에게 구체적인 안내 메시지 표시
권장  Canvas에서 외부 이미지 사용 시 프록시(/files/{id}/proxy) 경유

테스트 체크리스트

  • 로컬 Docker에서 /bending/base 페이지 정상 로드 (266건)
  • 로컬 Docker에서 /bending/products 페이지 정상 로드
  • API 미인증 시 안내 메시지 표시 확인
  • Canvas 편집기 이미지 로드 및 toDataURL 정상 동작
  • pint 코드 스타일 검사 통과

관련 문서

  • api/app/Http/Middleware/ApiKeyMiddleware.php — 화이트리스트 관리
  • mng/config/services.phpservices.api.base_url, services.api.internal_url 설정
  • mng/app/Services/FormulaApiService.phpresolveApiConnection() 참조 구현