🐕Proxy
우선 프록시 서버가 무엇인지 간단히 알아보고 리액트 프록시에 대해 알아보도록 하겠습니다.
혹시 글에 오류가 있다면 알려주세요..
https://ko.wikipedia.org/wiki/%ED%94%84%EB%A1%9D%EC%8B%9C_%EC%84%9C%EB%B2%84
wikipedia에서는 프록시 서버를 다음과 같이 설명합니다.
클라이언트가 자신을 통해서 다른 네트워크 서비스에 간접적으로 접속할 수 있게 해주는 컴퓨터 시스템
간접적으로 , 자신을 통해서라는 키워드로 알 수 있듯이 클라이언트와 서버사이에서 무언가를 중개해주는 일을한다. 라고 인식할 수 있습니다. Proxy는 사전적으로 대리(행위) , 대리권, 대리 투표, 대리인 등을 뜻한다고 하는데 클라이언트 대신에 어떠한 일을 수행하는 서버라는 의미로 프록시 서버라는 명칭이 붙지 않았나 싶네요
이러한 프록시 서버는 서버와 클라이언트 사이의 중계를 담당하며 클라이언트가 수행해야할 통신을 클라이언트 대신 수행해주기 때문에 프록시 서버라고 부릅니다. 프록시 서버는 단순히 중계만을 담당하는 경우도 있을수...있지만 이 외에도 다양한 역할을 수행하는 프록시 서버도 존재합니다. 예컨대 프록시 서버 중 일부는 요청된 내용들을 캐싱하여 저장해두며 캐싱 된 정보를 요청하는 경우엔 자신이 저장해둔 캐시데이터를 반환시키는 것으로 전송시간 절약 , 외부 연결 줄이기 등의 장점을 갖게하는 경우 또한 존재합니다.
프록시 자체는 굉장히 넓은 영역에서 많이 사용되는 언어이기에 우선 네트워크로 범위를 좁혀 프록시에 대해 다루도록 하겠습니다. 네트워크에서 프록시 서버는 크게 두가지로 나누어 볼 수 있는데 바로 포워드 프록시(forward proxy)와 리버스 프록시(reverse proxy) 두개입니다! MDN의 설명에 따르면 두 프록시의 정의는 다음과 같습니다.
https://developer.mozilla.org/ko/docs/Glossary/Proxy_server
포워드 프록시 | 리버스 프록시 |
인터넷 상에서 어디로든지 리퀘스트를 전송해준다. | 인터넷에서 리퀘스트를 받으면 내부 망의 서버로 전송해준다. |
우리가 주로 다루게 될 영역은 포워드 프록시에 가깝겠네요! 포워드 프록시는 클라이언트측을 대행해주고 리버스 프록시는 서버측을 대행해주는 느낌이라고 이해할수도 있을 것 같아요 포워드 프록시와 정반대의 일을 수행하니까 reverse 프록시라고 부르는 거군요! MDN이 말하는 프록시 서버의 정의도 꽤 이해가 잘 되어서 복사해와보자면 프록시는 "리퀘스트를 가로챈 뒤 리스폰스를 돌려주는" 일을 수행합니다. 가로챈 리퀘스트를 전달해줄 수도 전달하지 않을 수도 있습니다.(앞서 캐싱을 하면 굳이 요청을 보내지 않고 캐싱된 데이터를 반환해준다고 했었죠?) 또한 리퀘스트를 수정할 수도 있습니다.(서로 다른 두 네트워크 간의 경계에서 헤더를 바꾸는 경우를 들 수 있다고 합니다.)
이런 프록시는 사용자의 로컬 컴퓨터에 존재할 수도 있고 인터넷 상에서 사용자의 컴퓨터와 목표 서버 사이의 그 어느곳에든 존재할 수 있습니다. 인터넷에 익숙하신 분들은 프록시 서버가 뭔지는 모르더라도 한번쯤은 익숙하게 들어보셨을 단어일 것 같아요 저는 프록시가 뭔지는 모르지만.. 들어는 본 사람 중 하나거든요
그럼 여기까지 알아본 프록시에 대한 내용을 통해 포워드 프록시의 특징을 다음과 같이 정리해볼 수 있습니다.
포워드 프록시의 특징 |
캐싱을 수행하여 네트워크 통신을 절감할 수 있다. |
익명성이 보장된다 (서버는 프록시 서버의 요청에 응답하는 것이지 실제 그 요청을 한 클라이언트가 누구인지 알 수 없다.) |
그럼 Reverse Proxy에 대해서도 특징을 짚어볼까요?
리버스 프록시는 포워드 프록시에서는 고려하지않는 특징을 하나 더 추가해서 정리할 수도 있는데 바로 로드밸런싱입니다. 로드 밸런싱은 간단하게 생각하면 요청을 분산시켜 부하를 줄여주는 방법론 중 하나이다.라고 생각할 수 있습니다.
리버스 프록시의 특징 |
캐싱을 수행하여 네트워크 통신을 절감할 수 있다. |
보안성에 장점이 있다. (서버의 정보를 클라이언트로부터 숨기는 것이 가능하다. 즉 실제 서버의 IP가 클라이언트에게 노출되지 않는다.) |
로드밸런싱을 프록시서버가 수행해주는 경우도 있습니다. (로드밸런싱을 수행하지 않는 경우도 있어요!) |
👻react proxy로 들어가보자
이제 프록시서버가 무엇인지는 알게되었습니다. 그런데 개발 환경에서 프록시는 왜 필요할까요? 여러가지 이유가 있을 수 있습니다. CORS 정책을 우회하고자 사용하는 경우(CORS 정책은 브라우저 대 서버 통신일 때 적용되는 정책입니다. 따라서 서버 대 서버로 통신하는 경우에는 CORS 정책을 우회하는 것이 가능합니다. proxy 서버를 두는 것으로 서버 대 서버로 통신이 가능해지니 CORS 정책을 우회하는 것도 가능한 것이지요!) 도 있을 수 있고 여러가지 이유가 있을 수 있어요
위의 간단한 그림은 개발환경에서 직접 구축한 백엔드 서버와의 소통이 필요할 때 일반적으로 구성되는 환경을 나타낸 그림입니다. 우선 브라우저에 보여줄 react로 만든 우리의 예쁜 웹페이지를 보여줄 개발 서버가 필요합니다. 따라서 일반적으로 많이 사용하는 localhost:3000 포트에 우리의 웹페이지를 띄웠습니다. 우리는 http://localhost:3000으로 우리가 개발한 리액트 애플리케이션에 접근할 수 있겠죠?
그런데 우린 우리가 직접 만든 백엔드 서버와 리액트 애플리케이션을 연결해주고 싶은 상황에 놓였다고 가정해보겠습니다. 당연히 백엔드 서버도 직접 포트를 열어주고 개발 서버를 구동시켜줘야할 것입니다. 간단하게 만든 백엔드 서버를 열고 localhost:3000은 이미 리액트 애플리케이션이 점유중이니 다른 포트번호를 지정하여 백엔드 서버를 구동시켜줍니다. 우리의 백엔드 서버에는 이제 http://localhost:3001로 접근할 수 있어졌습니다.
이 때 프록시 설정을 이용한다고 가정하면 클라이언트 서버에게 요청이 들어오면 우선 요청을 보내보고 만약에 요청이 실패하면 자동으로 localhost:3001에게 요청을 보내도록해!
라고 알려주면 된답니다. 아니 근데 그거 어케함? 우선 CRA로 구성한 환경에서는 웹팩이 프록시와 관련된 설정을 담당해준다고 합니다. package.json의 프로퍼티에 proxy key를 추가해주면 됩니다.
package.json...
{
...(여러가지 프로퍼티들)
proxy:'http://localhost:3001',
}
이렇게 package.json을 수정해주고 나면
fetch('http://localhost:3001/api_path')
fetch('/api_path')
원래는 위와같이 절대경로로 작성해주어야 했던 fetch 요청 주소를
아래와 같이 상대경로의 형태로 축약해줄 수 있습니다.
이렇게 되면 아래와 같이 축약해서 작성했을때 요청은 다음과 같이 이루어집니다.
1. 우리가 만든 리액트 애플리케이션(localhost:3000)은 상대경로의 형태로 들어온 /api_path를 보고 http:localhost:3000/api_path를 자신이 가지고 있는지 확인해봅니다.
2. 자신에게 없는 주소라는 것을 알게 된 애플리케이션은 package.json에 명시된 proxy 프로퍼티의 밸류를 기반으로 요청을 보냅니다.
3. http://localhost:3001/api_path로 리액트 애플리케이션은 요청을 보냈으니 우리의 백서버는 요청을 받고 리액트 애플리케이션에게 응답을 보내줍니다.
4. 리액트 애플리케이션은 우리의 백엔드 서버로부터 받은 응답을 기반으로 브라우저에게 대신 응답을 합니다.
조금 생소할 수 있지만 쉽게 생각하면 우리가 구성한 리액트 애플리케이션 서버가 프록시 서버의 역할을 수행한다고 생각하면.. 됩니다. 원래의 구조로 생각해보면 다음과 같은 형태로 요청과 응답이 이루어질 것입니다.
1. 우리가 구성한 리액트 애플리케이션을 개발자는 브라우저로 접속하여 애플리케이션을 이용합니다.
2. 모종의 이벤트로 인하여 브라우저는 우리의 백엔드 서버에 요청을 보내게됩니다.
3. 백엔드 서버는 브라우저의 요청에 대한 응답을 작성하여 브라우저로 응답을 보냅니다.
물론 이과정에서 브라우저의 프리플라이트 요청으로 인해 CORS 에러가 발생할 수도 있겠지만 편의상 그 부분은 생략하고 서술하였습니다. 근데 전 vite을 이용하고 싶으니까 vite docs에서 관련된 내용을 찾아보도록 하겠습니다.
https://vitejs-kr.github.io/config/server-options.html
vite에서는 vite.config.js 파일에서 서버 옵션을 설정해주는 것을 통해 프록시 설정을 해줄 수 있습니다.
위 문서에 따르면 server.proxy가 우리가 찾는 규칙이겠네요
키 프로퍼티가 있는 객체를 기대한다고 하고 ^로 시작하면 정규표현식으로 해석된다고 합니다.
export default defineConfig({
server: {
proxy: {
// 문자열만: http://localhost:5173/foo -> http://localhost:4567/foo
'/foo': 'http://localhost:4567',
// 옵션과 함께: http://localhost:5173/api/bar-> http://jsonplaceholder.typicode.com/bar
'/api': {
target: 'http://jsonplaceholder.typicode.com',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '')
},
// 정규식(RegEx)과 함께: http://localhost:5173/fallback/ -> http://jsonplaceholder.typicode.com/
'^/fallback/.*': {
target: 'http://jsonplaceholder.typicode.com',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/fallback/, '')
},
// 프락시 인스턴스 사용
'/api': {
target: 'http://jsonplaceholder.typicode.com',
changeOrigin: true,
configure: (proxy, options) => {
// proxy 변수에는 'http-proxy'의 인스턴스가 전달됩니다
}
},
// 웹소켓 또는 socket.io 프락시: ws://localhost:5173/socket.io -> ws://localhost:5174/socket.io
'/socket.io': {
target: 'ws://localhost:5174',
ws: true
}
}
}
})
공식문서의 예제는 다음과 같습니다.
proxy 부분에서 우리가 봤던것처럼 지정을 해주는 것을 볼 수 있는데 좀 더 세세한 지정도 쉽게 가능하네요! 세세한 옵션을 신경쓰지 않고싶다면 /foo의 예제와 같이 설정해줄 수 있겠습니다.
proxy: {
'/foo' : 'http://localhost:4567'
}
이 코드는 개발서버가 5173에서 구동되고있을때 5173/foo로 우선 확인을 해본 뒤 config.js의 내용을 따라
로컬호스트 4567로 요청을 보내게 하는 코드입니다.
vite에서는 자체적으로 cors와 관련된 설정을 개발환경에서는 모두 허용해주도록 설정이 되어있지만 vite이 아닌 다른 방식으로 프로젝트를 구성한 경우에는 이렇게 proxy를지정해주지 않으면서 cors 헤더를 적절히 작성해주지 않은 경우 cors 에러를 만나게 될 수 있기에 개발할 때 불편함이 있을 수 있었답니다.
추가로 이런 설정들은 개발환경에서만 적용되니 실제 배포환경과는 다를 수 있습니다.
이제 proxy를 설정하는 방법도 알았으니.. 그럼 20000
🐶레퍼런스
https://www.youtube.com/watch?v=YxwYhenZ3BE
https://www.youtube.com/watch?v=VaAWIAxvj0A
'Network' 카테고리의 다른 글
스위치에 대한 조금 더 깊은 이해 (0) | 2023.04.27 |
---|---|
ARP (Address Resolution Protocol) 프로토콜 정리 (0) | 2023.04.25 |
HTTPS (0) | 2023.04.21 |
www.google.com을 검색하면 무슨일이 생길까 (1) | 2023.04.20 |
HTTP를 찍먹 해보자. (0) | 2023.04.01 |