CORS(Cross-Origin Resource Sharing) 란?

- 교차 출처 자원 공유라는 말로 서로 다른 출처간에 리소스를 공유하는 것을 허용하는 정책을 의미한다.

- 서로 다른 출처 공유에 대해서는 기본적으로 제한되어있다. (이를 SOP라 한다.)

 

*SOP (Same-Origin Policy) : 같은 출처끼리만 리소스를 공유할 수 있다는 정책
HTML태그를 통한 이미지, CSS, Script 요청은 SOP에 제한이 되지 않음

 

 

Origin : 출처를 의미하며, URL구조 / 프로토콜 + 호스트 + 포트를 합친 것을 말함

Port가 다른 경우에 다른 출처로 인식한다.

HTTP 포트 : 80 / HTTP 포트 : 443 생략 가능

 

CORS가 정의된 이유

SOP(Same-Origin Policy)의 장점

동일 출처 정책을 지키면 외부 리소스를 가져오지 못해 불편하지만, 동일 출처 정책은 보안 취약점을 노린 공격을 방어할 수 있다.

그런데 이런 SOP에도 한계가 있다.

 

SOP의 한계

현실적으로는 외부 리소스를 참고하는 것은 필요하기 때문에 외부 리소스를 가져올 수 있는 방법이 존재해야 한다.

외부 리소스를 사용하기 위한 SOP의 예외 조항이 CORS다.

 

1. Simple request (단순 요청 방법은 서버에게 바로 요청을 보내는 방법)

단순 요청은 서버에 API를 요청하고, 서버는 Access-Control-Allow-Origin 헤더를 포함한 응답을 브라우저에 보낸다. 브라우저는 Access-Control-Allow-Origin 헤더를 확인해서 CORS 동작을 수행할지 판단한다.

 

단순 요청으로 동작하기 위해서 서버로 전달하는 요청(request)이 만족해야하는 조건

1) 요청 메서드는 GET, HEAD, POST 중 하나여야 한다.

2) Accept, Accept-Language, Content-Language, Content-type, DPR, DOwnlink, Save-Data, Viewport-Width, Width 의의 헤더를 사용하면 안된다.

3) Content-type 헤더는 application/x-www-form-urlencoded, multipart/form-data, text/plain 중 하나를 사용해야 한다.

 

Preflight request

서버에 예비 요청을 보내서 안전한지 판단한 후 본 요청을 보내는 방법

실제 리소스를 요청하기 전에 OPTIONS이라는 메서드를 통해 실제 요청을 전송할지 판단한다.

OPTIONS 메서드로 서버에 예비 요청을 먼저 보내고, 서버는 이 예비 요청에 대한 응답으로 Access-Control-Allow-Origin 헤더를 포함한 응답을 브라우저에 보낸다. 브라우저는 단순 요청과 동일하게 Access-Control-Allow-Origin 헤더를 확인해서 CORS 동작을 수행할지 판단한다.

 

Preflight를 날리는 이유

브라우저가 CORS를 지원하지 않은 서버에 도달하면 요청에 대한 응답을 보내지 않아 실제 요청이 수행되지 않도록 보호하기 위함.

먼저 OPTIONS 메서드를 통해 다른 도메인의 리소스로 HTTP 요청을 보내 실제 요청이 전송하기에 안전한지 확인한다. cross-origin 요청은 유저 데이터에 영향을 줄 수 있기 때문에 이와같이 미리 전송(preflighted)합니다.

 

CORS 에러 해결 방법

- 서버에서 응답 헤더에 특정 헤더를 포함하는 방식으로 해결할 수 있다.

Access-Control-Allow-Origin : 특정 origin이 리소스에 접근이 가능하도록 허용한다.

Access-Control-Allow-Method : 특정 HTTP Method만 리소스에 접근이 가능하도록 허용한다.

Access-Control-Expose-Headers : JavaScript에서 헤더에 접근할 수 있도록 허용한다.

 

credentials request에 대해서는 추후에 추가 예정.

 

https://jakapark.tistory.com/68

 

[디자인 패턴] MVC 패턴에 대해서 간단히 알아보는 글

들어가기 전백엔드와 DB 기본을 공부하던 중 기초 디자인 패턴중인 MVC 패턴에 대해서 알게 됐다. 디자인 패턴이란 기존 환경 내에서 반복적으로 일어나는 제들을 어떻게 풀어나갈 것인가에 대

jakapark.tistory.com

 

며칠 전에 MVC 패턴에 대해서 알아보았다. (윗글 참고)

오늘은 MVC 패턴 예제 코드를 작성해보려고 한다.

 

MVC에 대해서 간단히 알아보자면

Model : 데이터를 처리
View : 유저가 보이는 화면
Controller : Model과 View를 이어주며 유저의 요청을 담당한다

 

.env 파일

DB_CONNECT = "MongoDBURI"

Config.js [./config/dbConnect.js]

// mongoose를 이용하여 MongoDB 연결
const dbConfigure = async () => {
  try {
    const connect = await mongoose.connect(process.env.DB_CONNECT);
    console.log("DB Connection Success")
  } catch(err) {
    console.log("DB Connection Fail")
  }
}

module.exports = dbConfigure;

app.js (엔드포인트 파일)

const express = require("express");
const dbConnect = require("./config/dbConnect")
const mongoose = require("mongoose");

const app = express();
const router = express.Router();

require("dotenv").config();

// view engine 사용
app.set("view engine", "ejs");
app.set("views", "./views");

// mongoDB 연결
dbConnect();

// routing
app.get("/", (req, res) => {
  res.send("Hello World");
});

// Middleware 추가
app.use(express.json()); // body에서 json 데이터를 추출하여 사용 가능
app.use(express.urlencoded({extended: true}));

// 라우팅 미들웨어
app.use("/contacts", require("./routes/contactRoutes"));

// Server 연결
app.listen(3000, () => {
  console.log("Server On~~~");
});

라우트 처리 / routes.js [./routes/routes.js]

const express = require("express");
const { getAllContacts, createContact } = require("../controllers/Controller");
const router = express.Router();

router.route("/").get(getAllContacts).post(createContact);
router.route("/:id").get((req, res) => {
  res.send(`${req.params.id} 리스트 확인`);
});

module.exports = router;

모델 / model.js [./models/models.js]

const mongoose = require("mongoose");

const shema = new mongoose.Schema(
  {
    name: {
      type: String,
      required: true
    },
    email: {
      type: String
    },
    phone: {
      type: String,
      required: [true, "전화번호를 꼭 입력해주세요!"]
    },
  },
  { timestamps: true }
);

// 스키마 -> 모델
const Contact = mongoose.model("Contact", schema);

module.exports = Contact;

 

컨트롤러 / controller.js [./controller/controller.js]

const Contact = require("../models/Model");

const getAllContacts = async (req, res) => {
  res.send("Contacts Page");
};

const createContact = async (req, res) => {
  const { name, email, phone} = req.body;
  
  if( !name || !email || !phone ){
    return res.send("필수 값이 입력되지 않았다.");
  }
  const contact = await Contact.create({ name, email, phon });
  res.send("Create Contacts");
};

module.exports = { getAllContacts, createContact };

 

View (ejs 파일 생략)

'BackEnd > Express' 카테고리의 다른 글

CORS (Cross-Origin Resource Sharing)에 대해서  (0) 2025.02.24
[NodeJS/Express] Express에 대해서  (0) 2024.06.29

목차

1. Express란?

2. Express 설치

3. Express 사용

 

1. Express란?

NodeJs의 프레임워크로써 http net으로 구현 가능한 네트워크 TCP를 모던한

느낌으로 외장모듈로 라이브러리를 구현한것이다.

NodeJs로만 사용하여 라우팅을 처리하려면 상당히 번거로운 작업을 해야했다.

Express를 사용하면 HTTP 모듈 기능 외에도 다양한 기능이 포함되어 있어서 유용하게 쓸 수 있다

 

1) 라우팅

HTTP 모듈을 사용할 때는 if 문이나 switch 문으로 요청 메서드나 요청 URL에 따라 라우팅 해야했다.

 

2) 미들웨어

Express에는 미들웨어라는 개념이 있어서 요청과 응답 사이에서 여러가지 기능을 실행할 수 있다.

(미들웨어가 많아서 가져와서 사용이 가능)

 

3) 템플릿 엔진

HTML 페이지는 기본적으로 정적이지만 서버와 함께 사용해서 동적인 HTML 페이지를 만들 수 있다.

(애플리케이션에셔 View를 담당)

 

4) 정적인 파일 지원

Express에서 동적인 파일만 생성하는 것은 아니다. CSS, JS, 이미지처럼 동적인 파일을 쉽게 서비스 할 수 있음

 

 

2. Express 설치

npm init -y

 

package.json 초기화를 해준다.

 

npm i expresss

 

Express의 최신 버전이 설치된다.

(협업할 때  팀원들 간의 express의 버전이 같지 않을 경우 호환성 문제 발생할 수 있어서 같은 버전을 사용해야한다.

package-lock.json 실제 버전 설치된 내용의 json 파일이 있으면 버전이 문제가 없다.)

 

3. Express 사용

// 외장 라이브러리
const express = require('express');

// 서버 객체 생성
const app = express();

 

app에는 express()의 리턴값이 들어가 있다.

express() 리턴값으로는 Application이라는 객체를 반환하는데, Application이라는 객체는 여러 메서드를 가지고 있다.

그 중 하나가 대표적으로 get, post 가 있다.

// 미들웨어
// express.json body의 내용을 파싱해서 객체로 변환
app.use(express.json());

// 쿼리스트링 파싱, form의 내용을 파싱
// 깊은 객체까지 사용 여부
app.use(express.urlencoded({ extended : true }));

 

미들웨어 : 요청을 보내고 응답을 하기 전에 처리할 내용

// 메서드로 라우팅
// get, post, put, delete

app.get('/', (req, res) => {
  console.log(req.query)
  // req.query : 쿼리스트링 객체로 파싱
  
  console.log(req.body);
  // req.body : 전달한 본문의 내용을 body에 객체 파싱
  
  res.send(`
  <html>
        <title>응답 페이지</title>
        <body>
            <form method="post" action="/postContent">
             <input type="text" name="test2">
             <button>확인</button>
            </form>
        </body>
    </html>
  `)
  // 응답 메시지 응답 종료
});

app.post('/postContent', (req, res) => {
  console.log(req.body);
  
  //redirect : 해당 경로로 다시 요청을 보냄
  res.redirect('/');
});

app.listen(3000, () => {
  console.log('서버 대기 상태');
})

+ Recent posts