테커 기능구현 챌린지에 참여해 검색기능을 구현하던 중, CORS 에러를 마주하였다.
이번 포스팅에서는 해당 에러를 해결한 과정에 대하여 정리해보려한다.
시작하기에 앞서, 개발 환경은 익숙한 Vite + React 가 아닌 Next 를 사용하였다.
Figma
- EndPoint : https://api.clinicaltrialskorea.com/api/v1/studies/?offset=0&limit=10&conditions={검색어}
- ex) 검색어에 ‘갑상선’을 넣었을 경우
{ "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)
}
}
하지만, 콘솔창을 켜 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" 에 설정한 주소로 프록시 시켜주는 방법이다.
하지만 내 예상과는 달리 해결이 되지 않았다.
프록시를 우회하는 방법에 실패하고 다른 해결책을 생각해봤다. 현재 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
문제는 해결하지 못하였다.. 추후에 해결하게 된다면 해당 과정을 꼭 정리해보겠다.