본문 바로가기

WINK-(Web & App)/Express.js (Node.js) 스터디

[2023 백엔드 스터디] 조다운 #6 주차 - 10.5 장~10.8 장 웹 API 서버 만들기

반응형

10.5 SNS API 서버 만들기

  • GET /post/my router : 내가 올린 포스트를 가져옴
  • GET /posts/hastag/:title router : 해시태그 검색 결과를 가져옴
const request = async (req, api) => {
  try {
    if (!req.session.jwt) { // 세션에 토큰이 없으면
      const tokenResult = await axios.post(`${URL}/token`, {
        clientSecret: process.env.CLIENT_SECRET,
      });
      req.session.jwt = tokenResult.data.token; // 세션에 토큰 저장
    }
    return await axios.get(`${URL}${api}`, {
      headers: { authorization: req.session.jwt },
    }); // API 요청
  } catch (error) {
    if (error.response?.status === 419) { // 토큰 만료시 토큰 재발급 받기
      delete req.session.jwt;
      return request(req, api);
    } // 419 외의 다른 에러면
    throw error;
  }
};
  • request 함수는 NodeBird API 에 요청을 보내는 함수 / 자주 재사용되므로 함수로 분리
  • 요청의 헤더 origin 값을 localhost:4000 으로 설정
  • 토큰 만료시 419 에러 → 토큰을 지우고 request 함수를 재귀적으로 호출해 다시 요청
  • localhost:4000/search/노드
    • 노드 해시태그를 사용한 글들을 보여줌

10.6 사용량 제한 구현하기

  • 인증된 사용자라고 해도 과도하게 API 를 사용하면 API 서버에 무리
    • 일정 기간 내 API를 사용할 수 있는 횟수를 제한해 서버의 트래픽을 줄이는 것이 좋음
  • $ npm i express-rate-limit
    • 사용량을 제한하는 기능을 가진 npm 패키지
  • verifyToken 미들웨어 아래 apiLimiter 미들웨어와 deprecated 미들웨어를 추가
// nodebird-api/middlewares/index.js

exports.apiLimiter = rateLimit({
  windowMs: 60 * 1000, // 1분
  max: 10,
  handler(req, res) {
    res.status(this.statusCode).json({
      code: this.statusCode, // 기본값 429
      message: '1분에 열 번만 요청할 수 있습니다.',
    });
  },
});

exports.deprecated = (req, res) => {
  res.status(410).json({
    code: 410,
    message: '새로운 버전이 나왔습니다. 새로운 버전을 사용하세요.',
  });
};
  • apiLimiter 미들웨어를 라우터에 넣으면 옵션으로는 windoMS (기준 시간), max(허용 횟수), handler(제한 초과 시 콜백 함수) 등이 있음
  • 현재 설정은 1 분에 한 번 호출 가능하게 되어 있으며, 사용량 제한을 초과하면 429 상태 코드와 함께 허용량을 초과했다는 응답을 전송
  • deprecated 미들웨어는 사용하면 안 되는 라우터에 붙여줌
    • 410 코드와 함께 새로운 버전을 사용하라는 메시지 응답
  • API 응답 목록
    • 200 : JSON 데이터
    • 401 : 유효하지 않은 토큰
    • 410 : 새로운 버전이 나왔음. 새로운 버전 사용
    • 419 : 토큰 만료
    • 429 : 1분에 한 번만 요청 가능
    • 500~ : 기타 서버 에러

10.7 CORS 이해하기

  • CORS(Cross-Origin Resource Sharing)
  • 실제 서비스에서는 서버에서 사용하는 비밀 키와 프런트에서 사용하는 비밀 키를 따로 두는 게 좋다. 보통 서버에서 사용하는 비밀 키가 더 강력하기 때문
  • 프런트에서 사용하는 비밀 키는 모든 사람에게 노출된다는 단점도 존재 → 따라서 데이터베이스에서 clientSecret 외에 frontSecret 같은 컬럼을 추가해 따로 관리하는 것을 권장

🚨 CORS 문제

  • Access-Control-Allow-Origin 이라는 헤더가 없다는 내용의 에러!
  • 브라우저와 서버의 도메인이 일치하지 않으면 기본적으로 요청이 차단됨
  • 브라우저 → 서버 요청일 때 이 현상 발생
    • 서버 → 서버 일 때는 발생하지 않음
  • 현재 콘솔에서 보이듯이 요청을 보내는 클라이언트 (localhost:4000) 와 요청을 받는 서버 (localhost:8002) 의 도메인이 다르다. → CORS 문제

CORS 문제 해결

  • CORS 문제를 해결하려면 응답 헤더에 Access-Control-Allow-Origin 이라는 헤더를 넣어야 함
    • 이 헤더는 클라이언트 도메인의 요청을 허락하겠다는 의미
    • 응답 헤더를 조작하려면 NodeCat이 아니라 NodeBird API 서버에서 바꿔야
    • 왜?
    • 응답은 API 서버에서 보내는 거기 때문
    • res.set 메서드로 직접 넣어도 되지만, npm 에 편한 패키지 cors 가 있음
  • $ npm i cors

CORS 옵션

  • credentials: true
    • 이 옵션 활성 → 다른 도메인 간에 쿠키 공유 가능
    • 프런트와 서버의 도메인이 다른 경우에는 이 옵션 활성 안 하면 로그인이 되지 않을 수 있음
  • withCredentials: true
    • axios 에서도 도메인이 다른데, 쿠키를 공유해야 하는 경우 이 옵션 활성해야함
  • Access-Control-Allow-Origin: *
      • 표시는 모든 클라이언트의 요청을 허용한다는 뜻
    • credentials: true 옵션은 이 헤더를 true 로 만듦

QUIZ

❓ Access-Control-Allow-Origin 가 true 가 된 덕에 새로운 문제가 생겼다. 요청을 보내는 주체가 클라이언트라 비밀 키(process.env.CLIENT_SECRET) 가 모두에게 노출된다. 이 문제를 해결하기 위해 할 수 있는 방법으로 옳은 것은?
  1. 필요한 때에만 옵션을 허용했다가 말았다 한다.
  2. 처음 비밀 키 발급 시 허용한 도메인을 적게 한다.
  3. 견딘다.
  4. * 표시를 작성하지 않고, 모든 클라이언트가 아닌 일부의 요청만을 허락한다.

ANSWER

2번! 호스트와 비밀 키가 모두 일치할 때만 CORS 를 허용하게 수정하면 된다.

가장 많이 나온 오답! 3.견딘다... 견디는 동아리 WINK...

➕ 프록시 서버

  • CORS 문제를 해결하는 다른 방법으로는 프록시(대리인) 서버를 사용하는 것이 있음
  • 서버 → 서버 요청 때 CORS 문제가 발생하지 않는다는 것을 이용한 방법

10.8 프로젝트 마무리하기

  • API 는 다른 애플리케이션의 기능을 사용할 수 있게 해주는 창구
    • 현재 NodeCat 이 NodeBird 의 API 를 사용하고 있음
  • 모바일 서버를 구성할 때 서버를 REST API 방식으로 구현하면 됨
  • API 사용자가 API 를 쉽게 사용할 수 있도록 사용 방법, 요청 형식, 응답 내용에 관한 문서를 준비하자
  • JWT 토큰의 내용은 공개되며 변조할 수 있다는 점을 기억하자
    • 단 시그니처를 확인하면 변조되었는지 체크할 수 있음
  • 토큰을 사용해 API 의 오남용을 막을 수 있음 → 요청 헤더에 토큰이 있는지를 항상 확인하는 것이 좋음
  • app.use 외에도 router.us 를 활용해 라우터 간에 공통되는 로직을 처리할 수 있음
  • cors 나 passport.authenticate 처럼 미들웨어 내에서 미들웨어를 실행할 수 있음
    • 미들웨어를 선택적으로 적용하거나 커스터마이징할 때 이 기법을 사용
  • 브라우저와 서버의 도메인이 다르면 요청이 거절된다는 특성(CORS)을 이해하자
    • 서버와 서버 간의 요청에서는 CORS 문제가 발생하지 않는다

10.9 진짜 마무리하기

작고 귀여운 페이지를 만들 수 있었던 유익한 시간이 되었습니다!!

우여곡절 끝에 만든 페이지이에요... 오타 질문까지 받아주신 스터디장 님과 그리고 독점했던 Node.js 교과서 무한한 감사와 영광 돌립니다... 

+ 실시간으로 발표 응원해준 연진 언니에게도 감사 완전 드립니다

반응형