Skip to content

TIL -2024-02-04 [Network,glich practice, CORS]Β #11

@Sewoni

Description

@Sewoni

πŸ‹TIL - 2024-02-04-Tuesday

πŸ“š 였늘의 ν•™μŠ΅

  • πŸ€ μ£Όμš” ν•™μŠ΅ λ‚΄μš© 1: λ„€νŠΈμ›Œν¬ μš”μ²­
    Fastify, fetch, async/await, axios
  • πŸ€ μ£Όμš” ν•™μŠ΅ λ‚΄μš© 2: glitch λ₯Ό ν†΅ν•œ Gemini λ₯Ό μ΄μš©ν•œ μ›Ήμ‚¬μ΄νŠΈ 배포.
const path = require("path");  // path λͺ¨λ“ˆμ„ λΆˆλŸ¬μ™€μ„œ 파일 경둜 κ΄€λ ¨ μž‘μ—…μ„ ν•  수 있게 함
const axios = require('axios');  // axiosλ₯Ό μ‚¬μš©ν•΄ HTTP μš”μ²­μ„ 보내기 μœ„ν•΄ 뢈러옴

const fastify = require("fastify")({
  logger: true,  // Fastify μ„œλ²„μ—μ„œ λ‘œκΉ… κΈ°λŠ₯을 ν™œμ„±ν™”ν•˜μ—¬ μš”μ²­κ³Ό 응닡을 둜그둜 좜λ ₯ν•  수 있게 함
});

fastify.get("/", async function (request, reply) {  // 루트("/") κ²½λ‘œμ— λŒ€ν•œ GET μš”μ²­μ„ μ²˜λ¦¬ν•˜λŠ” μ—”λ“œν¬μΈνŠΈ μ •μ˜
  const { GEMINI_KEY } = process.env;  // ν™˜κ²½ λ³€μˆ˜μ—μ„œ GEMINI_KEY 값을 μ½μ–΄μ˜΄
  
  if (!GEMINI_KEY) {  // λ§Œμ•½ GEMINI_KEYκ°€ ν™˜κ²½ λ³€μˆ˜μ— μ—†μœΌλ©΄
    return reply.status(500).send({ error: "GEMINI_KEY ν™˜κ²½ λ³€μˆ˜κ°€ μ„€μ •λ˜μ§€ μ•Šμ•˜μŠ΅λ‹ˆλ‹€." });  // 500 μ—λŸ¬μ™€ ν•¨κ»˜ λ©”μ‹œμ§€λ₯Ό λ°˜ν™˜
  }

  console.log("GEMINI_KEY:", GEMINI_KEY);  // GEMINI_KEY 값을 λ‘œκΉ…

  const url = `https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash:generateContent?key=${GEMINI_KEY}`;  // API μš”μ²­μ„ 보낼 URL 생성 (GEMINI_KEYλ₯Ό ν¬ν•¨ν•œ URL)

  try {
    const response = await axios.post(url, {  // POST μš”μ²­μ„ λ³΄λ‚΄μ„œ APIλ‘œλΆ€ν„° 데이터λ₯Ό λ°›μ•„μ˜΄
      contents: [  // μš”μ²­ 본문에 포함할 데이터 μ •μ˜
        {
          parts: [
            {
              text: "였늘 μš΄λ™μ„ κ°ˆκΉŒμš” λ§κΉŒμš”? νƒ€λ‹Ήν•œ 이유. ν•΅μ‹¬λ§Œ.",  // 질문 ν…μŠ€νŠΈ
            },
          ],
        },
      ],
    });

    const json = response.data;  // 응닡 받은 데이터λ₯Ό JSON ν˜•νƒœλ‘œ νŒŒμ‹±

    const answer = json.candidates[0].content.parts[0].text;  // JSONμ—μ„œ ν•„μš”ν•œ 닡변을 μΆ”μΆœ

    return answer;  // μΆ”μΆœν•œ 닡변을 ν΄λΌμ΄μ–ΈνŠΈμ— λ°˜ν™˜

  } catch (error) {  // API 호좜 쀑 μ—λŸ¬κ°€ λ°œμƒν–ˆμ„ 경우
    console.error("Error during API call:", error);  // μ—λŸ¬λ₯Ό 둜그둜 좜λ ₯
    return reply.status(500).send({ error: "API 호좜 쀑 였λ₯˜κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€." });  // 500 μ—λŸ¬μ™€ ν•¨κ»˜ λ©”μ‹œμ§€λ₯Ό λ°˜ν™˜
  }
});

fastify.listen(
  { port: process.env.PORT || 3000, host: "0.0.0.0" },  // μ„œλ²„κ°€ μš”μ²­μ„ 기닀릴 ν¬νŠΈμ™€ 호슀트 μ§€μ •
  function (err, address) {
    if (err) {  // μ„œλ²„κ°€ μ‹œμž‘ν•  λ•Œ 였λ₯˜κ°€ λ°œμƒν•˜λ©΄
      console.error(err);  // 였λ₯˜λ₯Ό 둜그둜 좜λ ₯
      process.exit(1);  // μ„œλ²„λ₯Ό μ’…λ£Œ
    }
    console.log(`Your app is listening on ${address}`);  // μ„œλ²„κ°€ μ •μƒμ μœΌλ‘œ μ‹œμž‘λ˜λ©΄ μ£Όμ†Œλ₯Ό 좜λ ₯
  }
);

.env api key μž…λ ₯

Image

이 μ½”λ“œμ—μ„œλŠ” CORSλ₯Ό μ²˜λ¦¬ν•˜μ§€ μ•ŠκΈ° λ•Œλ¬Έμ—, λ‹€λ₯Έ λ„λ©”μΈμ—μ„œμ˜ μš”μ²­μ„ 받을 λ•Œ CORS μ—λŸ¬κ°€ λ°œμƒν•  수 μžˆλ‹€. λΈŒλΌμš°μ €λŠ” λ³΄μ•ˆμƒ λ‹€λ₯Έ λ„λ©”μΈμ—μ„œ μ˜€λŠ” μš”μ²­μ„ 기본적으둜 μ œν•œν•˜λ©°, 이λ₯Ό ν•΄κ²°ν•˜λ €λ©΄ μ„œλ²„μ—μ„œ λͺ…μ‹œμ μœΌλ‘œ CORS 정책을 μ„€μ •ν•΄μ•Ό 함.

🚨 문제 상황

  • ν΄λΌμ΄μ–ΈνŠΈμ—μ„œ API μš”μ²­μ„ λ³΄λ‚΄λŠ”λ°, CORS μ—λŸ¬κ°€ λ°œμƒν•˜μ˜€λ‹€.

Image

🎯 μ‹œλ„ν•œ κ³Όμ •

  • Fastify μ„œλ²„λ₯Ό μƒμ„±ν•˜κ³  μ™ΈλΆ€ APIλ₯Ό ν˜ΈμΆœν•˜λŠ” μ½”λ“œ μž‘μ„± 쀑, λ‹€λ₯Έ λ„λ©”μΈμ—μ„œμ˜ μš”μ²­μ— λŒ€ν•œ λ³΄μ•ˆ μ •μ±…μœΌλ‘œ CORS λ¬Έμ œκ°€ λ°œμƒν•¨.

πŸ› οΈ ν•΄κ²° 방법

  • @fastify/cors ν”ŒλŸ¬κ·ΈμΈμ„ μ‚¬μš©ν•˜μ—¬ μ„œλ²„μ—μ„œ CORS 정책을 λͺ…μ‹œμ μœΌλ‘œ μ„€μ •ν•¨μœΌλ‘œμ¨ λͺ¨λ“  λ„λ©”μΈμ—μ„œμ˜ μš”μ²­μ„ ν—ˆμš©ν•˜λ„λ‘ λ³€κ²½ν•˜μ˜€λ‹€. 이λ₯Ό 톡해 CORS μ—λŸ¬λ₯Ό ν•΄κ²°.
const path = require("path");
const axios = require('axios');

const fastify = require("fastify")({
  logger: true, // λ‘œκΉ…μ„ ν™œμ„±ν™”
});

// npm install @fastify/cors@8
// fastify-cors ν”ŒλŸ¬κ·ΈμΈ μΆ”κ°€
fastify.register(require('@fastify/cors'), {
  origin: "*", // λͺ¨λ“  λ„λ©”μΈμ—μ„œ μš”μ²­μ„ ν—ˆμš©
});

fastify.get("/", async function (request, reply) {
  // ν™˜κ²½ λ³€μˆ˜κ°€ μ œλŒ€λ‘œ λ‘œλ“œλ˜μ—ˆλŠ”μ§€ 확인
  const { GEMINI_KEY } = process.env;
  
  if (!GEMINI_KEY) {
    return reply.status(500).send({ error: "GEMINI_KEY ν™˜κ²½ λ³€μˆ˜κ°€ μ„€μ •λ˜μ§€ μ•Šμ•˜μŠ΅λ‹ˆλ‹€." });
  }

  console.log("GEMINI_KEY:", GEMINI_KEY);

  const url = `https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash:generateContent?key=${GEMINI_KEY}`;
  
  try {
    const response = await axios.post(url, {
      contents: [
        {
          parts: [
            {
              text: "μ–΄λ–‘ν•˜λ©΄ 학생듀이 μ €ν•œν…Œ μ§‘μ€‘ν•΄μ€„κΉŒμš”? 20자 μ΄λ‚΄λ‘œ. ν•΅μ‹¬λ§Œ.",
            },
          ],
        },
      ],
    });

    // JSON ν˜•νƒœλ‘œ 응닡이 였기 λ•Œλ¬Έμ—, λ³„λ„λ‘œ JSON.parseλ₯Ό ν•  ν•„μš” 없이 λ°”λ‘œ μ‚¬μš© κ°€λŠ₯
    const json = response.data;

    // μ‘λ‹΅μ˜ ꡬ쑰에 맞게 ν•„μš”ν•œ 값을 μΆ”μΆœ
    const answer = json.candidates[0].content.parts[0].text;
    
    return answer;  // κ²°κ³Όλ₯Ό ν΄λΌμ΄μ–ΈνŠΈμ—κ²Œ λ°˜ν™˜

  } catch (error) {
    console.error("Error during API call:", error);
    return reply.status(500).send({ error: "API 호좜 쀑 였λ₯˜κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€." });
  }
});

fastify.listen(
  { port: process.env.PORT || 3000, host: "0.0.0.0" },
  function (err, address) {
    if (err) {
      console.error(err);
      process.exit(1);
    }
    console.log(`Your app is listening on ${address}`);
  }
);

🐳 λŠλ‚€ 점

  • CORSλŠ” 기본적으둜 λ‹€λ₯Έ λ„λ©”μΈμ—μ„œ μ˜€λŠ” μš”μ²­μ„ μ°¨λ‹¨ν•˜λŠ” λ³΄μ•ˆ μ •μ±…μœΌλ‘œ, 이λ₯Ό ν•΄κ²°ν•˜λ €λ©΄ μ„œλ²„μ—μ„œ CORS 헀더λ₯Ό μ„€μ •ν•΄μ•Ό ν•œλ‹€λŠ” 점을 μ΄ν•΄ν•˜μ˜€λ‹€. origin: "*" μ„€μ •μœΌλ‘œ λͺ¨λ“  λ„λ©”μΈμ—μ„œ μš”μ²­μ„ ν—ˆμš©ν•˜κ²Œ 됨.
  • 결둠적으둜, VScodeμ—μ„œ 둜컬 μ„œλ²„κ°€ λ‹€λ₯Έ 도메인에 μš”μ²­μ„ 보낼 λ•Œ CORS λ¬Έμ œκ°€ λ°œμƒν•  수 있으며, 이λ₯Ό ν•΄κ²°ν•˜κΈ° μœ„ν•΄μ„œλŠ” μ„œλ²„ μΈ‘μ—μ„œ CORSλ₯Ό ν—ˆμš©ν•΄μ£Όμ–΄μ•Ό ν•œλ‹€. κΈ€λ¦¬μΉ˜ μ„œλ²„μ—μ„œλŠ” CORS λ¬Έμ œκ°€ λ°œμƒν•˜μ§€ μ•Šμ§€λ§Œ, μš”μ²­μ„ λ°›λŠ” μ„œλ²„κ°€ CORS 섀정을 ν•΄μ•Όλ§Œ μ •μƒμ μœΌλ‘œ 데이터λ₯Ό 받을 수 μžˆλ‹€.

πŸ‘©β€πŸ’» μ°Έκ³  자료

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions