코드
/*
* 파일명: main.js
* 생성일: 2021-02-07
* 최종 수정일: 2021-02-08
* 설명: Web 백엔드 서버 개발 공부: Rest API with MySQL
*/
import express from "express";
import bodyParser from "body-parser";
import { dbConnection } from "./lib/db.js";
const server = express();
server.use(bodyParser.json());
// GET cmembers 데이터, /api/member/get-all로 접속하여 데이터 수신
server.get("/api/member/get-all", (req,
res) => {
let sqlQuery = "SELECT * FROM CMembers"; // query string
try {
dbConnection.query // send query to MySQL
(
sqlQuery
, function (err, rows, fields) {
if (err) { // error occured
res.status(500).send("Internal Server Error");
console.log(err);
}
else {
res.send(rows);
}
}
)
} catch (e) {
console.log(e);
}
});
// POST cmembers 데이터, /api/member/add에 JSON 형식으로 리퀘스트를 전송해 데이터 추가
server.post("/api/member/add", (req,
res) => {
console.log(req.body);
let reqJson = req.body; // JSON 형식으로 리퀘스트 온 데이터 변환
let resString = { // 유효성을 체크하기 위한
idValidance: "Valid",
NameValidance: "Valid",
MajorValidance: "Valid",
PhoneNumberValidance: "Valid",
EmailValidance: "Valid",
GradeValidance: "Valid",
ValidData: true,
PostSucceeded: false
};
// 유효하지 않은 데이터를 거르기 위한 string 필터
let nameFormat // 특수문자 제외
= /[ `!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?~]/;
let majorFormat // 한글만 포함
= /[ `!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?~abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ]/;
let phoneNumberFormat // +와 숫자만 포함
= /[ `!@#$%^&*()_\-=\[\]{};':"\\|,.<>\/?~abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"]/;
// filter id
if (reqJson['Id'] < 10000000 || reqJson['Id'] > 99999999)
{
resString.ValidData = false;
resString.idValidance = "Invalid Id Taken";
}
// filter Name
if (nameFormat.test(reqJson['Name']))
{
resString.ValidData = false;
resString.NameValidance = "Invalid Name. No special characters allowed.";
}
// filter Major
if (majorFormat.test(reqJson['Major']))
{
resString.ValidData = false;
resString.MajorValidance = ("Invalid Major Name. No special characters and alphabets allowed.");
}
// filter PhoneNumber
if (phoneNumberFormat.test(reqJson['PhoneNumber']))
{
resString.ValidData = false;
resString.PhoneNumberValidance = ("Invalid Phone number. + is the only special character allowed.");
}
// filter Email
if (!reqJson['Email'].includes("@")
|| reqJson['Email'].split('@')[0].length < 1
|| reqJson['Email'].split('@')[1].length < 1)
{
resString.ValidData = false;
resString.EmailValidance = ("Invalid Email Address.");
}
// filter Grade
if (reqJson['Grade'] < 1 || reqJson['Grade'] > 10)
{
resString.ValidData = false;
resString.GradeValidance = ("Invalid Grade.");
}
if (resString.ValidData) // 요청받은 데이터가 유효하다면
{
let sqlQuery = // INSERT 쿼리를 보낸다
"INSERT INTO CMembers (Id, Name, Major, PhoneNumber, Email, Grade, Comment) "
+ "VALUES ("
+ "\"" + reqJson['Id'] + "\"" + ","
+ "\"" + reqJson['Name'] + "\"" + ","
+ "\"" + reqJson['Major'] + "\"" + ","
+ "\"" + reqJson['PhoneNumber'] + "\"" + ","
+ "\"" + reqJson['Email'] + "\"" + ","
+ "\"" + reqJson['Grade'] + "\"" + ","
+ "\"" + reqJson['Comment'] + "\""
+ ")";
dbConnection.query(sqlQuery, function (err, rows, fields) {
if (err)
{
console.log(err);
resString.PostSucceeded = false;
}
else
{
console.log(rows);
resString.PostSucceeded = true;
}
});
}
res.send(resString);
});
// 서버 시작
server.listen(3000, () => {
console.log("Server Running");
});
결과
오류 해결 기록
ERR_NOT_SUPPORTED_AUTH_MODE
현재 서버에서 활용하고 있는 MySQL은 8.0.23-0ubuntu0.20.04.1 (Ubuntu)
버전이다. 즉 MySQL 8이다. MySQL 8부터는 SHA2 방식으로 암호화한 authentication_string
을 활용해 사용자를 인증한다. 하지만 현재 설치되어 있는 Node.js는 아직 해당 기능을 지원하지 않아 위 오류가 발생한다.
다양한 해결 방법이 있는데, 다음과 같다.
- 방법 1) 서버의 MySQL 인증 방식을 Legacy (MySQL 5.0)으로 전환한다.
- 방법 2) 서버의 MySQL에서 사용자의 IDENTIFY 방식을 mysql_native_password에서 임의로 정한 비밀번호로 바꾼다.
이전에 같은 서버에 ASP.NET with MVC를 활용했을 때 정상적으로 작동하였으므로, node.js에서의 문제로 판단하였다. 모든 클라이언트에서 접속할 때 사용할 인증 방식을 바꾸는 것은 현재 상황에서 비합리적이라고 판단하였다. 나는 방법 2를 선택했다.
MySQL 서버 내 유저의 인증 방식 변경
새로운 유저를 생성하여 해당 유저는 임의의 비밀번호를 통해 인증하도록 할 수 있다. 과정은 다음과 같다.
// 1. 유저 생성
CREATE USER 'username'@'ip-constraint' IDENTIFIED BY 'password';
// 2. 원하는 데이터베이스의 권한 부여
GRANT ALL PRIVILEGES ON database.* to 'username'@'ip-constraint';
// 3. 권한 적용
FLUSH PRIVILEGES;
// 4. mysql_native_password로 인증되던 방식을 임의의 비밀번호를 사용한
// 인증으로 변경
ALTER USER 'username'@'ip-constraint' IDENTIFIED
WITH mysql_native_password BY 'arbitrary-password';
// 5. 권한 적용
FLUSH PRIVILEGES;
ERR_MODULE_NOT_FOUND
추가할 모듈의 경로가 잘못되어 발생한 오류이다. lib
폴더에 저장한 db.js
파일에 접근하려 하였으나 경로를 lob
로 입력하여 오류가 발생하였다.
SyntaxError: The requested module does not provide an export named 'default'
당시 추가할 모듈에서 export
하는 방식을 숙지하지 못하여 발생한 오류이다. export
할 변수 선언문 앞에 해당 키워드를 붙여 해결하였다.
// 수정 전
let dbConnection = mysql.createConnection({
host: 'ip-address',
user: 'user-id',
password: 'password',
database: 'db-name'
});
// 수정 후
export let dbConnection = mysql.createConnection({
host: 'ip-address',
user: 'user-id',
password: 'password',
database: 'db-name'
});
ERR_HTTP_HEADERS_SENT
이미 전송한 respond에 다시 send()
를 사용하였을 경우 헤더를 다시 설정할 수 없어 발생하는 오류이다. GET 혹은 POST 이후 send()의 사용은 한 번씩만 해야 한다.
ER_PARSE_ERROR
JS Script 내에서 보낸 쿼리문이 유효하지 않을 때 발생하는 에러이다. 이 오류가 출력되면 쿼리문을 정상적으로 작성했는지 확인할 필요가 있다. 위 사례는 INSERT 시 VALUE를 큰따옴표로 묶지 않아 발생한 오류이다. string 기반 쿼리문은 오타나 형식 문제에 취약하므로 철저히 확인할 필요가 있다.
'프로그래밍 > BackEnd Study - Node.js, Docker' 카테고리의 다른 글
2021-02-12 인프라 구축에 관하여 (0) | 2021.03.07 |
---|---|
2021-02-11 AWS EC2 서버에 Docker Image 받고 실행하기 (0) | 2021.03.07 |
2021-02-10 Docker로 NodeJS 서버 배포하기 (0) | 2021.03.07 |
2021-02-07 변수의 선언과 고찰 (0) | 2021.03.07 |
Uploaded by Notion2Tistory v1.1.0