🔄 구성 흐름
- [프론트엔드] 프론트엔드에서 입력값 유효성 검사를 통해 잘못된 값은 서버에 보내지 않음
- [백엔드] 백엔드는 Express로 서버를 구성하고, CORS 문제 해결
- [데이터베이스] MongoDB에 Mongoose를 통해 사용자 정보를 저장
1. 프론트엔드 (React)
✅ 정규표현식 이용한 유효성 검사
정규 표현식은 문자열에서 특정 패턴을 찾거나 검증, 대체하는 강력한 도구
- 입력값이 올바른지 먼저 검사해서 잘못된 데이터는 서버에 보내지 않도록 처리
- 에러 메시지를
setState
를 통해 바로바로 UI에 반영
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
| // 사용자명: 영문자로 시작 + 영문자/숫자 4자 이상
const validateUsername = value => {
if (!value) return setErrUsername('')
if (!/^[a-zA-Z][a-zA-Z0-9]{3,}$/.test(value)) {
setErrUsername('사용자명은 영문자로 시작하는 4글자 이상의 영문자 또는 숫자여야 합니다.')
} else {
setErrUsername('')
}
}
// 비밀번호: 4자 이상
const validatePassword = value => {
if (!value) return setErrPassword('')
if (value.length < 4) {
setErrPassword('패스워드는 4자 이상이어야 합니다.')
} else {
setErrPassword('')
}
}
// 비밀번호 확인: 위의 비밀번호와 일치해야 함
const validatePasswordCheck = (value, current = password) => {
if (!value) return setErrPasswordOk('')
if (value !== current) {
setErrPasswordOk('패스워드가 일치하지 않습니다.')
} else {
setErrPasswordOk('')
}
}
|
✅ 회원가입 핸들러
- 유효성 검사 실행
- 에러 존재 시 조기 리턴
- 문제 없을 경우 axios로 백엔드에 POST 요청
- 응답에 따라 상태 메시지 변경
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| const register = async e => {
e.preventDefault()
// 유효성 검사 실행
validateUsername(username)
validatePassword(password)
validatePasswordCheck(passwordOk, password)
// 에러가 있거나 입력값이 비어 있으면 요청 중단
if (errUsername || errPassword || errPasswordOk || !username || !password || !passwordOk) return
// 문제 없을 경우 axios로 백엔드에 POST 요청
try {
setRegisterState('등록중')
const response = await axios.post('http://localhost:3000/register', { username, password })
console.log('회원가입 성공', response)
setRegisterState('등록완료')
} catch (err) {
console.log('회원가입 실패', err)
}
}
|
✅ HTML 구조
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
| <form className={css.container} onSubmit={register}>
<input
type="text"
placeholder="사용자명"
value={username}
onChange={handleUsernameChange}
/>
<strong>{errUsername}</strong>
<input
type="password"
placeholder="패스워드"
value={password}
onChange={handlePasswordChange}
/>
<strong>{errPassword}</strong>
<input
type="password"
placeholder="패스워드 확인"
value={passwordOk}
onChange={handlePasswordOkChange}
/>
<strong>{errPasswordOk}</strong>
<button type="submit">가입하기</button>
</form>
|
2. 백엔드 (Express)
✅ Express 서버 설정
package.json
에 type 추가
서버 기본 코드
1
2
3
4
5
6
7
8
9
10
11
| import express from "express";
const app = express();
const port = 3000;
app.get("/", (req, res) => {
res.send("Hello World!");
});
app.listen(port, () => {
console.log(`${port}번 포트에서 실행 중`);
});
|
서버 실행 UI
✅ CORS 에러
프론트와 백엔드를 연동했더니 CORS 에러 발생 !
CORS(Cross-Origin Resource Sharing)는 브라우저의 보안 정책 중 하나 !
서로 다른 출처(Origin)에서 리소스를 요청할 때 브라우저가 이를 차단할 수 있음
- 프론트 포트(5173)와 백엔드 포트(3000)가 다르기 때문에 CORS 에러가 발생함
express.json()
으로 body 데이터 파싱도 필요
해결방법 : cors
미들웨어 추가
특정 출처를 허용하면 브라우저가 요청을 허용하게 됨
1
2
3
4
5
| import cors from "cors";
app.use(cors()); // 모든 출처 허용 (개발 단계에서 편함)
// 선택적으로 특정 출처만 허용하려면
// app.use(cors({ origin: 'http://localhost:5173' }))
app.use(express.json()); // 프론트에서 전송한 JSON 데이터를 Express가 해석하도록.
|
- 브라우저가 보낸 JSON 데이터를 req.body로 받을 수 있고
- 프론트엔드의 CORS 에러도 발생하지 않게 됨
React에서 Express로 보낸 값 확인 가능
3. MongoDB 연결 (mongoose 사용)
✅ Mongoose란?
- MongoDB와 연결해주는 ODM(Object Data Modeling) 라이브러리
- 스키마 정의 및 모델 생성, 데이터를 쉽게 읽고 쓰게 해줌
1. 모델 생성
1
2
3
4
5
6
7
8
9
10
11
12
| import mongoose from "mongoose"
const { Schema, model } = mongoose
// username, password라는 필드를 갖는 users라는 컬렉션을 만든 것과 동일
const userSchema = new Schema({
username: { type: String, required: true, unique: true },
password: { type: String, required: true }
}, {
timestamps: true
})
export const userModel = model("user", userSchema)
|
mongoose.Schema()
로 스키마를 정의mongoose.model()
로 컬렉션을 생성
2. DB 연결 및 회원가입 API
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
| import express from "express";
import cors from "cors";
import mongoose from "mongoose";
import { userModel } from "./model/user.js";
const app = express();
const port = 3000;
app.use(cors());
app.use(express.json());
mongoose.connect(`mongodb+srv://{username}:{password}@cluster0.mongodb.net/blog?retryWrites=true&w=majority`)
.then(() => console.log("MongoDB 연결됨"))
.catch(err => console.log("MongoDB 연결 안됨", err))
app.get("/", (req, res) => {
res.send("Hello world");
});
app.post("/register", async (req, res) => {
const { username, password } = req.body
console.log("회원가입 요청", req.body)
// 1. userModel(DB) 에서 이미 존재하는 사용자인지 확인
const existingUser = await userModel.findOne({ username });
if (existingUser) {
return res.json({ message: "이미 존재하는 사용자입니다." });
}
// 2. 새 사용자 생성 및 저장
const userDoc = new userModel({ username, password });
const savedUser = await userDoc.save();
// 3. 성공 응답
res.status(201).json({
user: {
username: savedUser.username,
_id: savedUser._id,
},
});
});
app.listen(port, () => {
console.log(`${port} 포트에서 돌고 있음`);
});
|
MongoDB 연결된 모습
연결 후 콘솔에 “회원가입 성공”이 찍히는 모습
회원 정보가 MongoDB에 저장
connect 함수에서 ?retryWrites=true
뒤에 작성한 DB 이름인 blog
가 MongoDB에 생성됨
MongoDB에 “blog”라는 DB가 생기고 그 안에 데이터가 저장된 모습
END