들어가며
Vue3 프로젝트를 할때는 Vite 의 경우 vite.config , Webpack 의 경우 vue.config 파일을 통해 proxy 설정을 할 수 있다. 하지만 현재 2023-08-13 기준 Nuxt3 같은 경우에는 공식문서상 proxy 설정에 대한 설정을 찾아 볼 수 없다. Nuxt3 proxy 에 대해서는 Nuxt issue 에 많은 글들이 달렸는데 하나씩 써보면서 문제점과 결국 어떤것을 써야하는지 알아보자.
준비
Nuxt3 v3.6.5 과 Spring 을 이용해 간단히 만든다. 둘다 기본 포트인 Nuxt 3000번 포트, Spring 8080번 포트를 사용한다.
proxyTest.vue
<template>
<div>
<button @click="() => refreshFullPath()">refreshFullPath</button>
<div>fullPathData : {{ fullPathData }}</div>
<button @click="() => refreshRelativePath()">refreshRelativePath</button>
<div>relativePathData : {{ relativePathData }}</div>
<NuxtLink to="/">home</NuxtLink>
</div>
</template>
<script setup lang="ts">
const page = ref(0);
const { data: fullPathData, refresh: refreshFullPath } =
await useAsyncData<number>(() =>
$fetch("http://localhost:8080/min/api/test", {
params: { page: page.value++ },
}),
);
const { data: relativePathData, refresh: refreshRelativePath } =
await useAsyncData<number>(() =>
$fetch("/min/api/test", {
params: { page: page.value++ },
}),
);
console.log("fullPathData : ", fullPathData.value);
console.log("relativePathData : ", relativePathData.value);
</script>
TestController.java
@RestController
@RequestMapping("/min/api")
@Slf4j
public class TestController {
@GetMapping("/test/{no}")
public ResponseEntity<Long> testWithPathVariable(@PathVariable Long no) throws InterruptedException {
log.info("testWithPathVariable 호출 no : {}", no);
Thread.sleep(500);
return ResponseEntity.ok(no);
}
@GetMapping("/test")
public ResponseEntity<Map<String, Object>> testWithParam(@RequestParam Map<String, Object> data) throws InterruptedException {
log.info("testWithParam 호출 data : {}", data);
Thread.sleep(500);
return ResponseEntity.ok(data);
}
}
해당 위의 코드를 실행하면 문제가 발생한다. 어떤 문제가 발생하는지 알아보자.
상황
SSR
CSR
첫 페이지 요청시 일어나는 SSR 시에는 Nuxt 서버에서 바로 Spring 으로 Request 를 보내기때문에 fullPath 로의 요청은 성공해 응답을 받지만 relativePath 같은 경우에는 기본적으로 Nuxt 서버 자체의 Server 디렉토리를 바라보게 되는데 해당 API 가 존재하지 않으니 null 을 반환하게 된다.
router 를 이용해 페이지를 이동하는 경우인 CSR 시에는 fullPath 같은 경우에는 브라우저의 CORS 때문에 요청이 실패하며 relativePath 또한 존재하지 않는 리소스 요청이므로 404 에러가 난다.
(특이하게 CSR시 요청 실패를 두번하는것을 볼 수 있는데 이는 Nuxt 가 사용하고있는 $fetch(ofetch) 의 auto retry 옵션이 GET 요청의 경우 한번 더 실행하기 때문이다.)
이 문제는 Spring 의 CORS 설정을 통해 해결할 수 있지만 Nuxt 로는 어떻게 할 수 있는지 알아보자.
Vite
Nuxt3 는 nuxt.config 파일에 여러가지 설정을 넣을 수 있는데 그 중 vite 설정도 넣을 수 있다. 해당 설정을 적용해보자.
설정
// nuxt.config.ts
export default defineNuxtConfig({
vite: {
server: {
proxy: {
"/api": {
target: "http://localhost:8080",
changeOrigin: true,
},
},
},
},
})
결과
SSR
CSR
실행 결과를 보면 SSR 시에는 relativePath 의 요청은 실패해서 결과가 null이다. CSR 시에는 relativePath 는 성공적으로 Spring쪽에 요청한다. 그 이유는 SSR 환경에서는 vite의 proxy 설정을 타지 않고 요청을 보내고 CSR 환경에서는 proxy 설정이 정상적으로 타면서 요청을 보냈기 때문이다.
Nitro devProxy
위의 Nuxt issue 를 보다보면 Nuxt 팀에서 일하고있는 개발자가 답변한 내용이 있다. Nuxt3 의 내장서버인 Nitro 의 설정을 통한 proxy 설정을 할 수 있다고 한다. 하지만 잘 안된다는 댓글이 몇개 달려있다. 한번 적용 후 확인해보자.
설정
// nuxt.config.ts
export default defineNuxtConfig({
nitro: {
devProxy: {
"/min/api": {
target: "http://localhost:8080/min/api",
changeOrigin: true,
},
},
},
});
결과
SSR
CSR
해당 devProxy 설정또한 Vite 설정과 같은 문제를 가지고 있다.
Proxy middleware
Nuxt의 Server Middleware 를 통해 모든 요청을 가로챌 수 있다. 해당 기능을 이용해 특정 요청 url 을 Nuxt 에 기본 내장되어있는 proxyRequest 을 통해 요청을 감싸 사용 할 수 있다.
설정
// /server/middleware/proxy.ts
export default defineEventHandler(event => {
if (!event.node.req.url?.startsWith("/min/api")) return;
const target = new URL(event.node.req.url, "http://localhost:8080");
return proxyRequest(event, target.toString(), {
headers: {
host: target.host,
origin: target.origin,
},
});
});
결과
SSR
CSR
초기 SSR 에서 fullPath, relativePath 두가지 다 성공한 것을 볼 수 있다. 즉, Vite 설정이나 Nitro devProxy 설정과는 다르게 서버사이드에서 proxy 가 제대로 타고 있다는것을 확인 할 수 있다. 또한 CSR 요청도 정상적으로 proxy 되어 요청되는것도 확인 할 수 있다.
필자는 Nuxt3.0.0 버전부터 이것을 이용해 프로젝트를 정상적으로 개발 해왔다. 하지만 한가지 방법을 더 소개해보겠다.
Nitro rotueRules
2023-02 에 드디어 Nuxt3 에 Built-in proxy 기술이 들어왔다. 해당 기능은 위의 Nuxt issue 가 처음 나온 2021-10, built-in proxy 기능 PR 이 생긴 2022-04 이후 거의 1년만에 생긴것이다. 해당 기능은 Nitro 의 버전이 올라간 Nuxt3.2.0 버전부터 사용할 수 있다.
설정
// nuxt.config.ts
export default defineNuxtConfig({
nitro: {
routeRules: {
"/min/api/**": {
proxy: "http://localhost:8080/min/api/**",
},
},
},
});
결과
SSR
CSR
Proxy middleware 와 똑같이 성공하는모습을 볼 수 있다. 재미있는 사실은 기능은 Proxy middleware 의 코드와 비슷한 형태로 만들어져있다는것을 구현코드를 통해 확인할 수 있다.
결론
정상적인 proxy 방법을 사용하기 위해서는 Proxy middleware 나 Nitro routeRules 를 이용하면 된다. 필자는 Nitro routeRules 가 추가된 Nuxt 3.2.0v 이후에도 여전히 Proxy middleware 방법을 사용하고 있다. 그 이유는 요청을 가로챈 뒤 Logging 이나 요청 조작같은 처리를 넣기 편하기 때문이다. 각자 필요한 상황에 맞춰 사용하면 될것같다.
구현 코드는 여기서 확인 할 수 있다.
'front-end > nuxt' 카테고리의 다른 글
Nuxt3 log4js를 이용해 json log 출력하기(feat. EFK Stack) (0) | 2023.08.31 |
---|---|
Nuxt3 $fetch, useAsyncData, useFetch 의 차이 (5) | 2023.07.27 |
Nuxt3 의 Universal Rendering 이란 무엇인가.. (0) | 2023.07.06 |