Mixed Content 에러 해결하기 (feat: Vercel Serverless Function)

park.js·2024년 12월 3일
2

FrontEnd Develop log

목록 보기
34/37

Vercel Serverless Function으로 Mixed Content 에러 해결하기

문제 상황

HTTPS로 배포된 React 애플리케이션에서 HTTP API(서울시 문화행사 정보)를 호출하려고 할 때 Mixed Content 에러가 발생한다.
하필 서울시 open api는 https 프로토콜을 제공하지 않기 때문에

<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests

(https로 변환하는 방법) 위 방법도 안먹힌다.

// ❌ 직접 HTTP API를 호출하는 경우
fetch('http://openapi.seoul.go.kr:8088/API_KEY/json/culturalEventInfo/1/5/');
// Mixed Content 에러 발생!

원인

  • 보안상의 이유로 브라우저는 HTTPS 페이지에서 HTTP 리소스를 직접 불러오는 것을 차단한다
  • 사용자의 데이터를 보호하기 위한 보안 정책때문..

해결 방법

Vercel의 Serverless Function을 프록시로 사용하여 HTTP API 호출을 우회한다.

1. API 라우트 설정 (/api/events.js)

const axios = require('axios');

module.exports = async (req, res) => {
  try {
    // 서버 사이드에서 HTTP API 호출
    const API_KEY = process.env.REACT_APP_API_KEY;
    const response = await axios.get(
      `http://openapi.seoul.go.kr:8088/${API_KEY}/json/culturalEventInfo/1/5/`
    );

    // 응답 데이터 확인 및 반환
    if (!response.data.culturalEventInfo) {
      throw new Error(response.data.RESULT?.MESSAGE || 'API 호출 실패');
    }

    res.status(200).json(response.data);
  } catch (error) {
    console.error('Server Error:', error);
    res.status(500).json({
      error: true,
      message: error.message || 'Internal Server Error'
    });
  }
};

2. Vercel 설정 (vercel.json) (netlify도 당연히 가능함. 경로나 파일명만 살짝 달리해야함.)

{
  "version": 2,
  "rewrites": [
    {
      "source": "/api/:path*",
      "destination": "/api/:path*"
    }
  ]
}

3. React 컴포넌트에서 API 호출(App.js 일부)

const fetchEvents = async () => {
  try {
    // ✅ HTTPS로 제공되는 Vercel Function 호출
    const response = await fetch('/api/events');
    const data = await response.json();
    
    if (data.error) {
      throw new Error(data.message);
    }

    setEvents(data.culturalEventInfo.row || []);
  } catch (err) {
    console.error('Error details:', err);
    setError(err.message);
  }
};

전체 App.js 코드

import { useState, useEffect } from 'react';
import './App.css';

function App() {
  const [events, setEvents] = useState([]);
  const [error, setError] = useState(null);

  useEffect(() => {
    const fetchEvents = async () => {
      try {
        const response = await fetch('/api/events');
        console.log('Response status:', response.status);

        const data = await response.json();
        console.log('Response data:', data);

        if (data.error) {
          throw new Error(data.message);
        }

        setEvents(data.culturalEventInfo.row || []);
      } catch (err) {
        console.error('Error details:', err);
        setError(err.message);
      }
    };

    fetchEvents();
  }, []);

  if (error) {
    return <div>에러 발생: {error}</div>;
  }

  return (
    <div className="App">
      <h1>서울시 문화행사 정보</h1>
      {events.length === 0 ? (
        <p>로딩중...</p>
      ) : (
        <ul>
          {events.map((event, index) => (
            <li key={index} style={{marginBottom: '20px', textAlign: 'left'}}>
              <h3>{event.TITLE}</h3>
              <p>분류: {event.CODENAME}</p>
              <p>장소: {event.PLACE}</p>
              <p>날짜: {event.DATE}</p>
              <p>요금: {event.USE_FEE}</p>
              {event.MAIN_IMG && (
                <img 
                  src={event.MAIN_IMG}
                  alt={event.TITLE}
                  style={{maxWidth: '200px'}}
                />
              )}
            </li>
          ))}
        </ul>
      )}
    </div>
  );
}

export default App;

작동 원리

  1. 브라우저가 안전한 HTTPS 연결을 통해 Vercel Serverless Function을 호출한다.
  2. Serverless Function이 서버 사이드에서 HTTP API를 호출한다.
  3. 받아온 데이터를 다시 HTTPS를 통해 브라우저로 전달한다.
[브라우저] → HTTPS → [Vercel Function] → HTTP → [서울시 API]

브라우저: "물건이 왔는데 가져오기 무서워요.. Vercel Function님 대신 가져와주세요ㅎ" (브라우저가 Vercel Function에 HTTPS로 요청)

Vercel Function: 응 알겠어. 나는 브라우저가 아니라 서버라서 http/https 모두 가져올 수 있어. (Vercel이 서버에서 HTTP API 호출)

Vercel Function: 자 받아. 가져왔어. (Vercel이 데이터를 HTTPS로 브라우저에 전달)

구현 순서

  1. /api/events.js 파일 생성 및 서버리스 함수 구현
  2. vercel.json 설정으로 API 라우트 경로 매핑
  3. React 컴포넌트에서 API 호출 코드 수정
  4. Vercel 환경변수 설정 (REACT_APP_API_KEY)
  5. 배포 및 테스트

주의사항

  • 환경변수는 반드시 Vercel 대시보드에서도 설정해야 함.
  • 로컬 개발 환경에서는 .env.local 파일에 환경변수를 설정.
  • API 응답의 에러 처리를 반드시 구현해야 디버깅 편함

이렇게 Vercel Serverless Function을 활용하면 Mixed Content 에러를 해결하면서도 보안을 유지할 수 있다! 이것이 바로 서버리스 아키텍처라고 한다. 엥? vercel 서버를 사용하는데 왜 서버less 지? => 내가 서버 관리안하고 vercel서비스가 서버 관리를 해주므로 서버리스라고 하는 것이다.

profile
참 되게 살자

0개의 댓글