Next.js 환경에서 CORS 에러 해결

SOONJA·2024년 5월 16일
0

Trouble Shooting

목록 보기
1/1
post-thumbnail

Intro

테커 기능구현 챌린지에 참여해 검색기능을 구현하던 중, CORS 에러를 마주하였다.
이번 포스팅에서는 해당 에러를 해결한 과정에 대하여 정리해보려한다.
시작하기에 앞서, 개발 환경은 익숙한 Vite + React 가 아닌 Next 를 사용하였다.

Figma

기능 요구사항

{
    "count": 8,
    "next": null,
    "previous": null,
    "sponsored_studies": [],
    "results": [
        {
            "from_type": 1,
            "url": "https://api.clinicaltrialskorea.com/api/v1/studies/29262/",
            "id": 29262,
            "ct_id": "201900132",
            "locations": [],
            "phases": [
                "3상"
            ],
            "minimum_age_display": "18세",
            "maximum_age_display": null,
            "title": "이전 VEGFR 표적 요법 후 진행한 방사성요오드 치료저항성 분화 갑상선암 시험대상자에서 카보잔티닙(XL184)에 대한 제3상, 무작위배정, 이중 눈가림, 위약 대조 시험",
            "start_date": "2019-01-01",
            "completion_date": "2022-08-01",
            "lead_sponsor_name": "파머수티컬리서치어소시에이츠코리아",
            "brief_summary": "본 시험의 목적은 이전 VEGFR 표적 요법 후 진행한 RAI 저항성 DTC 시험대상자에서 위약과 비교하여 카보잔티닙이 PFS 및 ORR에 미치는 영향을 평가하는 것이다.",
            "gender": "남녀모두",
            "is_sponsor": false,
            "survey_id": null,
            "is_new": false,
            "created_at": "2021-10-26T19:18:06.531105"
        },
        {
            "from_type": 1,
            "url": "https://api.clinicaltrialskorea.com/api/v1/studies/27142/",
            "id": 27142,
            "ct_id": "202100156",
            "locations": [
                {
                    "city": "서울"
                }
            ],
            "phases": [
                "연구자 임상시험"
            ],
            "minimum_age_display": "18세",
            "maximum_age_display": "65세",
            "title": "갑상선 전절제술을 시행받는 환자에서 수술 전 비타민 D(디맥정 30,000 IU) 경구 투여의 수술 후 저칼슘혈증 예방 효용성 연구",
            "start_date": "2020-12-01",
            "completion_date": "2022-12-01",
            "lead_sponsor_name": "서울대학교병원",
            "brief_summary": "수술 전 비타민 D3(cholecalciferol) 경구 복용의 수술 후 저칼슘혈증 예방효과를 증명하고자 하는 연구자 임상시험이다.",
            "gender": "남녀모두",
            "is_sponsor": false,
            "survey_id": null,
            "is_new": false,
            "created_at": "2022-05-12T13:47:12.640427"
        },
        ...
    ]
}

먼저, 검색창에 입력한 텍스트를 state 로 관리하기 위해 SearchBar 컴포넌트를 클라이언트 컴포넌트로 변경하고 입력한 텍스트를 쿼리파라미터로 넣어 get 요청을 하였다.

  const getSearchResult = async () => {
    try {
      const response = await axios.get(
        `https://api.clinicaltrialskorea.com/api/v1/studies/?offset=0&limit=10&conditions=${searchTerm}`,
      )
      console.log('api 응답 : ', response)
    } catch (error) {
      console.error('API 요청 중 에러 발생:', error)
    }
  }

시도1) 프록시 우회

하지만, 콘솔창을 켜 response 를 확인해보니 CORS 에러가 발생하였다.

만약 프로젝트 협업과정에서 해당 에러가 발생하였다면, 서버 개발자가 access-control-allow-origin 을 허용해주어 간단하게 문제를 해결할 수 있다.

하지만 외부 API를 변경할 수 는 없기에 이에 해결책을 모색하던 중, 과거 Vite + React 를 사용한 프로젝트에서 프록시를 우회하여 CORS 에러를 해결했던 경험이 생각이 났다.

Next 에서는 프록시 우회를 해보지 않아 공식문서블로그를 참고하여 프록시 우회를 시도해보았다.

//next.config.mjs

/** @type {import('next').NextConfig} */
const nextConfig = {
  async rewrites() {
    return [
      {
        source: '/api/:path*',
        destination: 'https://api.clinicaltrialskorea.com/api/:path*',
      },
    ]
  },
}

export default nextConfig
  const getSearchResult = async () => {
    try {
      const response = await axios.get(
        `/api/v1/studies/?offset=0&limit=10&conditions=${searchTerm}`,
      )
      console.log('api 응답 : ', response)
    } catch (error) {
      console.error('API 요청 중 에러 발생:', error)
    }
  }

해당 방법은 사용자가 접근하는 URL 주소가 "/api"인 경우에 "destination" 에 설정한 주소로 프록시 시켜주는 방법이다.

하지만 내 예상과는 달리 해결이 되지 않았다.

시도2) Route Handler

프록시를 우회하는 방법에 실패하고 다른 해결책을 생각해봤다. 현재 Next.js 를 사용하고 있으므로 Next 서버와 외부 API 가 통신하는 Route Handler 를 시도해봤다.

//app/api/route.ts

import axios from 'axios'
import { NextRequest, NextResponse } from 'next/server'

export const GET = async (request: NextRequest) => {
  // 쿼리 파라미터에서 데이터 가져오기
  const searchParams = new URL(request.url).searchParams
  const searchTerm = searchParams.get('searchTerm') || '' // searchTerm 매개변수 추출

  try {
    // 외부 API로 통신
    const response = await axios.get(
      `https://api.clinicaltrialskorea.com/api/v1/studies/?offset=0&limit=10&conditions=${searchTerm}`,
    )
    return new NextResponse(JSON.stringify(response.data), {
      status: 200,
    })
  } catch (error) {
    console.log(error)
    return new NextResponse('server error', {
      status: 500,
    })
  }
}
  const getSearchResult = async () => {
    const response = await axios.get(`http://localhost:3000/api?searchTerm=${searchTerm}`)
    console.log('api 응답 : ', response)
  }
  • 클라이언트는 쿼리파라미터로 searchTerm(검색어)를 next.js 서버에게 전달
  • 외부 api 통신을 클라이언트가 아닌 next.js 서버에서 시도(서버 to 서버)
  • next.js 서버는 응답 결과를 클라이언트에게 전달

결과는 성공적이었다..!

후기

이번 챌린지에는 Next 스터디에서 학습했던 내용을 적용해보기 위해서 Next 프레임워크를 사용해보았다. 에러를 해결하고 나니 인프런 강의에서 배웠던 Route Handler 가 어렴풋이 생각이 났다..

생각보다 삽질을 오래한터라 굉장히 아쉬웠지만.. 이번 삽질과정도 한층 성장시켜줬을거라 생각한다.

그리고 사실은 프록시 우회를 시도했을때 발생한 ERR_TOO_MANY_REDIRECTS Error 문제는 해결하지 못하였다.. 추후에 해결하게 된다면 해당 과정을 꼭 정리해보겠다.

profile
developer

0개의 댓글

관련 채용 정보