본문 바로가기
Front-end/Vue3

40. Vue - netlify serverless function 설정

by devraphy 2021. 6. 23.

1. 사용 프로젝트 

https://github.com/akaRaphael/vue3-movie-app.git

 

akaRaphael/vue3-movie-app

movie app made of Vue 3. Contribute to akaRaphael/vue3-movie-app development by creating an account on GitHub.

github.com

 


2. 사용 목적 

- 위의 프로젝트는 netlify 무료 호스팅 서비스를 이용하여 실제로 빌드를 해놓았다. 

- 아래의 링크를 통해 확인할 수 있다. 

 

https://silly-banach-bd5250.netlify.app/#/

 

Hello Vue Project!

 

silly-banach-bd5250.netlify.app

 

- 위의 프로젝트에는 한가지 치명적인 보안 문제를 갖고 있다. 

- 내부적으로 영화 검색 API를 사용하기위해 등록해놓은 API key값이 그대로 드러나게 되어 있다는 것이다. 

- 아래의 사진을 참고하자 

클릭하면 확대됩니다. 

 

- 현재 프로젝트에서 사용하는 OMDbAPI 키는 가입만 하면 쉽게 얻을 수 있는 부분이기 때문에, 사실 크게 문제되는 부분이 아니다. 

- 하지만 이처럼 중요한 key값이 공개적으로 오픈되어 있다는 것은 웹 서비스를 제공하는 입장에서 보안상 큰 위험이 된다.

- 그러므로 이 문제를 해결하기 위해 serveless function을 사용한다.  

- 본 프로젝트는 배포 서비스를 netlify로 하고 있기 때문에 netlify의 servelss function을 사용한다는 점을 유의하자.

 


3. 공식문서 

https://docs.netlify.com/functions/configure-and-deploy/

 

Configure and deploy Functions

Netlify builds, deploys, and hosts your front end. Learn how to get started, see examples, and view documentation for the modern web platform.

docs.netlify.com

 

https://cli.netlify.com/netlify-dev#netlifytoml-dev-block

 

x0

What is Netlify Dev? Watch the introduction (24 minutes) Netlify Dev brings the power of Netlify's Edge Logic layer, serverless functions and add-on ecosystem to your local machine. It runs Netlify's production routing engine in a local dev server to make

cli.netlify.com

 

[Netlify serverless function의 작동방식]

- 아래의 전개도는 위의 공식문서 링크에서 확인할 수 있다. 

클릭하면 확대됩니다.

- 현재 프로젝트가 위의 그림에서 Project라고 가정해보자. 

- 현재 프로젝트가 동작하는 localhost의 포트번호는 8080이니 8080이라고 생각하자.

- 작동 순서는 다음과 같다. 

  1. 프로젝트가 8080포트에서 작동한다.
  2. Netlify Dev라는 별도의 개발서버를 열어서 현재 프로젝트를 가지고 온다.
  3. 작성한 serverless function을 프로젝트와 결합시켜 포트번호 8888번에서 프로젝트를 동작시킨다. 
  4. 동작된 프로젝트는 브라우저를 통해 사용자에게 출력된다.  

4. 설정 방법 

[파일 경로]

클릭하면 확대됩니다.

 

[functions 폴더 - hello.js 생성]

- 아래 코드는 실제 serverless 함수를 작성하기 이전에 환경구성을 위한 테스트용 코드입니다.

exports.handler = async function (event, context) {
  return {
    statusCode: 200,
    body: JSON.stringify({
      name: 'DEVRAPHY',
      email: 'devraphy@gmail.com'
    })
  }
}

 

 

[netlify.toml 생성]

# Netlify Dev
# https://cli.netlify.com/netlify-dev/

# 제품모드 
[build]
  command = "npm run build"
  functions = "functions" # Netflify 서버리스 함수가 작성된 디렉토리를 지정
  publish = "dist" # 프로젝트 빌드 결과의 디렉토리를 지정 

# 개발모드 
[dev]
  framework = "#custom" # 감지할 프로젝트 유형을 지정.
  command = "npm run dev" # 연결할 프로젝트의 개발서버를 실행하는 명령(script)을 지정 
  targetPort = 8080 # 연결할 프로젝트의 개발서버의 포트번호를 지정 
  port = 8888 # 출력할 Netlify 서버의 포트번호를 지정 
  publish = "dist" # 프로젝트의 정적 콘텐츠 디렉토리를 지정 
  autoLaunch = false # Netlify 서버가 준비되면 자동으로 브라우저를 오픈할 것인지 지정

  # ==> 서버 환경에 배포하지 않아도 로컬 환경에서 테스트가 가능해짐

 


[package.json]

- 아래 사진에 빨간 밑줄이 그어진 명령을 추가한다. 

- Netllify 서버를 통해 배포를 하지 않고도 배포 결과를 확인할 수 있도록 명령(script)를 등록한다. 

- 해당 명령을 사용하려면 Netlify CLI를 설치해야 한다. 

클릭하면 확대됩니다. 

 

[Netlify-CLI 설치]

  • 터미널 입력: npm i -D netlify-cli

 

[개발 환경에서 실행하기]

- 다음 명령어를 입력하면 아래와 같은 결과가 터미널에 출력되어야 한다.

- Netlify 서버를 거쳐 빌드되는 것이기 때문에 기존의 8080포트가 아니라 8888포트라는 것을 유의하자. 

  • 터미널 입력: npm run dev:netlify

클릭하면 확대됩니다.
클릭하면 확대됩니다.

 

[hello.js 연동 확인하기]

  • 주소창 입력: 기본 주소 뒤에 #을 지우고 /.netlify/functions/hello 를 입력한 후 확인


5. Serverless function 작성 

- 가장 문제가 되는 부분은 영화를 검색했을 때, API key가 공개된다는 부분이다.

- 해당 기능을 serverless 함수로 작성해보자. 

 

[문제가 된 함수 - store - movie.js]

클릭하면 확대됩니다.

- API key가 공개되는 문제를 갖고있는 메소드다. 

- 위의 메소드는 axios.get()을 사용하여 데이터가 넘어가기 때문에 데이터 보안의 문제를 갖고 있는 것이다. 

- 그러므로 데이터를 넘기는 과정을 post로 변경해주며, serverless 함수의 형태로 변경해 줄 것이다.

 

[functions - movie.js 생성]

// serverless function은 node js 환경에서 동작한다. 
// 그러므로 node js 환경에서는 import/export를 사용하지 않고 
// require/exports 라는 객체를 이용한다. 
const axios = require('axios') // axios 사용을 위한 패키지 가져오기 


exports.handler = async function(event) { // 사용 가능한 매개변수는 event와 context가 있다.  
  // serverless 함수는 반드시 비동기로 동작해야 한다.
  // 아래 내용은 영화 검색기능 부분인 _fetchMovies() 함수의 내용을 복붙한 후 수정한 코드다.
  console.log(event)
  // payload를 받아오는 방법 - 데이터를 주고 받을때, 용량의 문제로 데이터가 문자타입으로 넘어온다. 
  // payload는 JSON 객체 형태를 갖고 있기 때문에 JSON.parse()를 통하여 다시 JSON화 시켜준다. 
  const payload = JSON.parse(event.body)
  const { title, type, year, page, id} = payload
  const OMDB_API_KEY = '7035c60c'
  const url = id  // id값이 있는 경우와 없는 경우를 나눈 삼항연산자
  ? `https://www.omdbapi.com/?apikey=${OMDB_API_KEY}&i=${id}` 
  : `https://www.omdbapi.com/?apikey=${OMDB_API_KEY}&s=${title}&type=${type}&y=${year}&page=${page}`

  try { // 비동기 함수이므로 아래의 코드를 비동기 형태로 최적화 한다. 
    const {data} = await axios.get(url)
    if(data.Error) {
      return { 
        // netlify serverless 함수에 맞는 형태로 수정한다. 
        // netlify serverless 함수는 statusCode와 body를 반드시 반환해야 한다. 
        // body는 문자열만 작성할 수 있다. 
        statusCode: 400,
        body: data.Error // Error는 에러 메세지를 담고 있다 === 문자데이터
      }
    }
    return {
      statusCode: 200,
      body: JSON.stringify(data) 
      // data는 json 형태의 데이터를 갖고 있기 때문에
      // stringify를 사용하여 문자 형식으러 변경한다. 
    }

  } catch (error) {
    return {
      statusCode: error.response.status, // axios 공식문서 참조
      body: error.message
    }
  }
}

- 위의 코드를 살펴보면 event 객체를 콘솔에 출력하는 부분이 있다.

- event 객체가 담고있는 데이터를 확인하기 위함인데, 이 부분은 아래쪽에서 다시 언급하겠다.  

 

[store-movie.js의 기존 메소드 수정]

async function _fetchMovies(payload) {
  // GET이 아니라 POST를 사용하는 이유 - 보안
  // GET - 데이터를 URL에 포함시켜서 넘김 
  // POST - 데이터를 문자열로 변환하여 body에 담아서 전달함. URL에 표시안됨
  return await axios.post('/.netlify/functions/movie', payload) // 매개변수 - 전달할 페이지, 전달할 데이터

  // serverless 함수 사용으로 인해 더이상 사용하지 않는 코드 
  // const { title, type, year, page, id} = payload
  // const OMDB_API_KEY = '7035c60c'
  // const url = id  // id값이 있는 경우와 없는 경우를 나눈 삼항연산자
  // ? `https://www.omdbapi.com/?apikey=${OMDB_API_KEY}&i=${id}` 
  // : `https://www.omdbapi.com/?apikey=${OMDB_API_KEY}&s=${title}&type=${type}&y=${year}&page=${page}`

  // return new Promise((resolve, reject) => {
  //   axios.get(url) 
  //   .then((res) => {
  //     if(res.data.Error) {
  //       reject(res.data.Error)
  //     }
  //     resolve(res)
  //   })
  //   .catch((err) => {
  //     reject(err.message)
  //   }) 
  // })
}

6. 주의사항 

- 이제 영화검색 기능은 Netlify의 serverless 함수를 통하여 동작하게 된다. 

- 여기서 주의할 부분은 예외처리 부분이다. 

- 새로 작성한 serverless 함수를 보면 data.Error라는 에러 객체를 반환한다.

- 이전에 예외를 처리하던 방식은 프로젝트 내부에서 처리하는 방식으로, 네트워크 환경을 거치지 않았기 때문에 문자열 데이터로 처리가 가능했으나, serveless 함수를 이용하면서 부터 Netlify 서버를 거쳐 에러 데이터가 반환되기 때문에 이는 에러 객체가 반환되는 것이다.  

 

[store-movie.js의 searchMovies() 함수]

클릭하면 확대됩니다.

 

- 그러므로 해당 부분을 다음과 같이 수정해야 한다. 

클릭하면 확대됩니다.


7. event 객체 확인하기 

- 우선 npm run dev:netlify를 통해서 프로젝트가 잘 작동하는지 확인해보자. 

- 그리고 영화를 검색하여 serverless 함수가 잘 동작하는지 또한 확인해보자. 

- serverless 함수가 잘 동작한다면, event객체의 정보가 콘솔에 출력되어있을 것이다. 

 

[frozen을 검색한다면] 

클릭하면 확대됩니다.

- 우선, Request from이라는 가장 윗줄 부분을 확인해보자.

- post 방식으로 serverless 함수를 정의한 파일에서 요청이 잘 들어간 것을 확인할 수 있다. 

 

 

클릭하면 확대됩니다.

- 더불어, 아래쪽에 body를 통해 검색 요청을 할 때 어떤 데이터가 넘어갔는지 알 수 있다.  

- frozen이라는 검색어가 입력된 것을 확인할 수 있다. 

- 위의 데이터는 serverless 함수의 반환값이라는 것을 잊지말자.

 

 

[검색 결과를 클릭한다면]

- 검색된 영화 중 하나를 클릭하는 것도 요청이다. 

- 동일하게 serverless 함수를 통해 post 요청이 된 것을 확인할 수 있다. 

 

- 아래쪽의 body 부분을 확인하면, 검색 결과에서 선택한 특정 영화의 id값이 반환 되는 것을 알 수 있다. 

- 이처럼 API key의 노출없이 안전하게 데이터를 전송하고 반환받는 구조를 완성하였다. 

'Front-end > Vue3' 카테고리의 다른 글

42. Vue - 포트 수정 및 배포  (0) 2021.06.24
41. Vue - 로컬 및 서버의 환경변수 구성  (0) 2021.06.24
39. Vue - router 개념 정리  (0) 2021.06.21
38. Vue - vuex 개념 정리  (0) 2021.06.21
37. Vue - vuex helper  (0) 2021.06.21

댓글