웹 백엔드

Node.js - form

토리쟁이 2024. 1. 28. 05:38

 

 

이번 포스팅에서는 node.js에서 form을 통한 get/post 방식의 요청 처리에 대해 공부해 보도록 하겠다.


 

우선, form 태그에 대해 자세히 다뤄보자.

 

 

 

 

 

<form>

  • 입력된 데이터를 한 번에 서버로 전송하기 위해 사용
  • 클라이언트가 서버에게 정보를 전달할 때 사용
  • 속성: action, name, target, method
    • action: 폼을 전송할 서버 주소 지정
    • name: 폼을 식별하기 위한 이름
    • method: 폼을 서버에 전송할 http 메소드 지정
      • get
        • 정보를 가져오거나 검색할 때 사용
        • URL 쿼리 문자열에 데이터를 담아 전송(쿼리 스트링) → 양 제한적
        • 서버의 값이나 상태를 변경하지 않을 때 사용
      • post
        • 무언가를 생성하거나 어떠한 정보를 보낼 때 사용
        • 보내야하는 데이터는 요청(request)의 본문(body)에 담아 전송
        • 길이가 제한된 URL보다 더 많은 데이터를 body에 담아 전송 가능
    • target: action 속성값에 지정한 스크립트 파일을 어떤 방식으로 열 것인지 지정
      • "_blank": 새 창에서 열기(클릭시 계속 새로운 창이 생성됨)
      • "blank": 클릭하면 한번 열린 에서(새로운 탭이 열리는 것 X) 계속 새로운 페이지가 열림
      • "_self": 현재 창에서 열기
  • 폼 요소: <input>, <select>. <textarea>, <button>

 

 

 

폼 요소에는 input/ select/ textarea/ button 등이 있다고 했는데, 하나씩 자세히 살펴보자.

 

 

 

<input>

  • 사용자가 다양하게 폼 태그를 입력할 수 있게 하는 것
  • 입력창
  • 가장 기본적인 form 요소
  • 속성
    • type: input 타입
      • text / radio/ checkbox 등
    • name: 이름 지정 / 백엔드에서 name으로 key가 설정
    • readonly: 읽기 전용(수정 불가)
    • autofocus: 자동 focus 기능
    • placeholder: 짧은 도움말

 

 

 

<select>

  • 선택창
  • 서버가 지정한 특정 값만을 선택할 수 있는 요소

 

 

 

<label>

  • 폼 양식에 이름을 붙일 수 있음
  • for="" 속성 : 속성 값으로 연결할 요소의 id를 적어 label을 클릭해도 해당 요소로 가게 만들 수 있음

 

 

 

fieldset & legend

 

<filedset>

  • 폼 태그 안에 있는 요소들을 그룹화할 때 사용

<legend>

  • <fieldset> 안에 들어가는 태그로, 목적에 맞게 이름을 지정할 수 있음.

 

 

 


 

 

 

이제. form 태그에 대해 다뤄봤으니 서버를 통해 form에 입력한 데이터를 받아보자.

실습 코드를 보여주고 해당 코드에 대한 설명을 하는 방식으로 공부해 볼 것이다.

 

 

일단 뷰는 다음과 같다.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>form 배우기</title>
  </head>
  <body>
    <h1>GET 요청</h1>
    <form action="/getForm" method="get">
      <label for="">
        id:
        <input type="text" name="id" />
      </label>
      <br />
      <label for="">
        email:
        <input type="email" name="email" required />
      </label>
      <br />
      <label for="">
        password:
        <input type="password" name="pw" />
      </label>
      <button type="button">제출(button type)</button>
      <button type="submit">제출(submit type)</button>
    </form>

    <h2>POST 요청</h2>
    <form action="/postForm" method="post">
      <label for="id">ID</label>
      <input
        type="text"
        name="id2"
        id="id"
        placeholder="id를 입력해주세요"
        pattern="^([a-zA-Z0-9가-힣]){4,10}$"
        title="아이디는 영어 대소문자, 숫자, 한글로 이루어진 4자 이상 10자 이하로 입력해주세요"
        required
      />

      <label for="pw">비밀번호</label>
      <input
        type="password"
        id="pw"
        name="pw2"
        placeholder="비밀번호를 입력해주세요"
        pattern="^([a-z0-9]){8,12}$"
        required
      />
      <!--8자리부터 12자리까지 입력 가능-->

      <fieldset>
        <legend>체크박스</legend>
        <label for="">
          <input type="checkbox" name="agree" value="마케팅 동의" />마케팅
          동의</label
        >
        <br />
        <label for=""
          ><input type="checkbox" name="agree" value="개인정보 수집 동의" />
          개인정보 수집 동의</label
        >
        <br />
        <label for="">
          <input type="checkbox" name="agree" value="이용약관 동의" />이용약관
          동의</label
        >
      </fieldset>

      <label for=""></label>

      <input type="submit" value="제출" />
    </form>
    <form
      action="/js-form-check"
      method="post"
      name="validationForm"
      target="_blank"
      onsubmit="return checkForm(this)"
    >
      <input
        type="text"
        name="id"
        minlength="1"
        placeholder="ID를 입력해주세요"
        title="최소 한글자 이상을 입력해주세요"
        id="input"
      />
      <br />
      <div>우편물 수령 장소</div>
      <label for="">
        <input type="checkbox" name="mail" value="회사" required />회사
      </label>
      <label for="">
        <input type="checkbox" name="mail" value="자택" />자택
      </label>
      <button>제출</button>
    </form>
    <hr />
    <div>
      <a href="/practice1">실습문제1(GET)</a>
      <br />
      <a href="/practice2">실습문제2(POST)</a>
    </div>
    
    <script>
    // 유효성 검사를 위한 스크립트 작성
      function checkForm(form) {
        // console.log(form);
        // document.forms["네임 속성"]
        // const form = document.forms["validationForm"] // 폼 태그 중에서 validationForm 인 것

        // 바로 접근 가능
        console.log(form.input); // id 참조
        console.log(form.id); // name 참조

        /* input text 창에 아무 것도 쓰지 않았다면*/
        if (form.id.value === "") {
          alert("아이디를 입력해주세요");

          // submot 이벤트를 실행하지 않도록 false를 반환할 것
          return false;
        }
        /*체크박스에서 아무 것도 선택되지 않았다면*/
        if (form.mail[0].checked === false && form.mail[1].checked === false) {
          alert("우편물 수령 장소를 선택해주세요");
          return false;
        }
      }
    </script>
  </body>
</html>

 

실습 뷰 화면

 

위의 뷰 HTML에서 유효성 검사를 위한 script 코드는 나중에 살펴볼테니 일단 넘어가자.

이러한 뷰에서 GET 요청 아래에서 id와 email, password를 입력 후, submit 버튼을 누르면 입력된 데이터가 get 방식으로 /getForm 경로에 전달된다. 이렇게 전송된 데이터를 node.js에서 받기 위한 코드는 다음과 같다. 

 

 

 

 

GET 요청

// 모듈 불러오기
const express = require("express");
const app = express();
const PORT = 8089; // 원하는 포트 번호 지정

// 뷰 관련 설정
app.set("view engine", "ejs"); // 뷰를 ejs로 보여줄 것임을 미리 알려주기
app.set("views", "./views"); // ("views", "뷰가 들어있는 파일 경로명")


// get 방식
app.get("/getForm", function (req, res) { // "/getForm" 경로에 get 요청이 들어왔을 때

  // res.render('뷰', {보내줄 데이터}) : 뷰 페이지에 데이터를 보냄
  res.render("result", { // result 페이지에 보내줄 데이터
    title: "GET",
    // get 방식으로 전송할 경우, req.query에 정보가 담겨서 옴
    userInfo: req.query, // {id:'', email:'', pw:''}의 형태이며, req.query를 userInfo에 담음
  });
});

 

이렇게 받은 데이터를 result 페이지로 렌더링 시켜주면 된다.

 

result 페이지는 다음과 같다.

<!DOCTYPE html>
<html lang="ko">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>form 전송 결과</title>
    <!--
        title:'GET',
        userInfo: req.query, // {id:'', email:'', pw:''}
    -->
  </head>
  <body>
    <h1><%= title%>요청 확인하기</h1>
    <div>
      <span><%=userInfo.id%>(<%=userInfo.email%>)</span>님 환영합니다!
      <div>비밀번호는 <span><%=userInfo.pw%>이군요!</span></div>
    </div>
    <a href="/">홈으로 이동하기</a>
    <%# ejs 주석처리 방법 %>
  </body>
</html>

 

받은 데이터는 req.query에 담겨져 전달되고, 그 데이터를 다시 userInfo 객체에 넣어두었기 때문에, 점 표기법을 사용해 꺼내서 쓰기만 하면 된다. 참고로, key값이 input의 name 속성 값이다. 아래 사진은, 아이디로 khy, 이메일 khy@naver.com, 비밀번호 khy를 압력했을 때의 결과 화면이다.

 

주의할 점은, 쿼리 스크링에 데이터가 담겨서 전송되므로 데이터를 노출시키고 싶지 않은 경우엔 GET 방식의 사용을 지양해야한다.

GET 방식

 

 

 

 

다음은, post 요청 처리에 대해 공부해보자.

 

POST 요청

// 모듈 불러오기
const express = require("express");
const app = express();
const PORT = 8089; // 원하는 포트 번호 지정

// 뷰 관련 설정
app.set("view engine", "ejs"); // 뷰를 ejs로 보여줄 것임을 미리 알려주기
app.set("views", "./views"); // ("views", "뷰가 들어있는 파일 경로명")

// body-parser 미들웨어
app.use(express.urlencoded({ extended: true })); // body-parser 설정 (true/false 반환)
app.use(express.json()); // json 형식으로 데이터를 주고 받음


// post 방식
app.post("/postForm", function (req, res) { // "/getForm" 경로에 get 요청이 들어왔을 때
  
  // send와 rend 동시 사용 불가
  // res.render('뷰', {보내줄 데이터}) : 뷰 페이지에 데이터를 보냄
  res.render("result2.ejs", { // result2 페이지로 데이터를 전송
    title: "POST",
    // post는 request.body에 담겨져 옴
    userInfo: req.body, // {id2:'', pw2:'' agree:[]} 형태로 userInfo 객체에 담아 전송
  });
});

 

이렇게 받은 데이터를 result 페이지로 렌더링 시켜주면 된다.

 

 

중간 10번째 줄에 body-parser 미들웨어에 대한 설정이 이뤄졌는데, body-parser이 뭔지 알아보자.

 

body-parser

  • 데이터를 쉽게 처리할 수 있도록 도와주는 미들웨어
  • 요청(request)의 body를 해석해서 데이터를 req.body 객체로 받을 수 있게 도와줌
  • 즉, POST 요청시 데이터가 담기는 req.body를 사용하기 위해 쓰이는 것
  • express 4.x부터 body-parser이 내장되어 있어 따로 설치 필요 없음

 

 

result2 페이지는 다음과 같다.

<!DOCTYPE html>
<html lang="ko">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>form 전송 결과</title>
    <!--
        title:'post',
        userInfo: req.body, // {id:'', pw:'', agree:[]}
    -->
  </head>
  <body>
    <h1><%= title%>요청 확인하기</h1>
    <div>
      <span><%=userInfo.id2%></span>님 환영합니다!
      <div>비밀번호는 <span><%=userInfo.pw2%>이군요!</span></div>
    </div>
    <a href="/">홈으로 이동하기</a>
    <%# ejs 주석처리 방법 %>
  </body>
</html>

 

받은 데이터는 req.body에 담겨져 전달되고, 그 데이터를 다시 userInfo 객체에 넣어두었기 때문에, 점 표기법을 사용해 꺼내서 쓰기만 하면 된다. 참고로, key값이 input의 name 속성 값이다. 아래 사진은, 아이디로 khy, 비밀번호 1234564789를 압력했을 때의 결과 화면이다.

 

 

 

 

 

추가적으로, 유효성 검사에 대해 알아보도록 하자.

 

 

form validation(유효성 검사)

  • form 요소들에 정보가 올바르게 입력되었는지 검사하는 것(조건 검사)
  • ex) 비밀번호: 8자리 이상, 특수문자 및 대문자 1개 이상 포함
  • required: 필수입력
  • minlength/maxlength: 최소/최대 문자수
  • min/max: 최소/최대 값
  • type: 입력받는 정보 타입
  • pattern: 정규식으로 검사

 

 

 

폼의 유효성 검사를 하기 위해서는 form의 속성에서 양식 제출 이벤트가 발생할 때의 동작을 지정해주는 속성인  onsubmit을 걸어주고 그 속성값에 만들어 둔 유효성 검사 함수를 넣어주면 된다. 

 

<form
      action="/js-form-check"
      method="post"
      name="validationForm"
      target="_blank"
      onsubmit="return checkForm(this)"
    >
      <input
        type="text"
        name="id"
        minlength="1"
        placeholder="ID를 입력해주세요"
        title="최소 한글자 이상을 입력해주세요"
        id="input"
      />
      <br />
      <div>우편물 수령 장소</div>
      <label for="">
        <input type="checkbox" name="mail" value="회사" required />회사
      </label>
      <label for="">
        <input type="checkbox" name="mail" value="자택" />자택
      </label>
      <button>제출</button>
    </form>

 

 

가운데의 input을 보면 속성으로 type,name, ,minlength 등 유효성 검사 속성들이 작성된 것을 알 수 있다. 참고로, title 속성은 커서 올리면 뜨는 작은 도움말 창? 이라고 생각하면 된다. 

그리고 form 속성의 onsubmit에서 유효성 검사 함수를 호출하면 된다.

onsubmit="return checkForm(this)

 

 

 

유효성 검사 함수는 다음과 같다.

<script>
      function checkForm(form) {
        // console.log(form);
        // document.forms["네임 속성"]
        // const form = document.forms["validationForm"] // 폼 태그 중에서 validationForm 인 것

        // 바로 접근 가능
        console.log(form.input); // id 참조
        console.log(form.id); // name 참조

        /* input text 창에 아무 것도 쓰지 않았다면*/
        if (form.id.value === "") {
          alert("아이디를 입력해주세요");

          // submot 이벤트를 실행하지 않도록 false를 반환할 것
          return false;
        }
        /*체크박스에서 아무 것도 선택되지 않았다면*/
        if (form.mail[0].checked === false && form.mail[1].checked === false) {
          alert("우편물 수령 장소를 선택해주세요");
          return false;
        }
      }
    </script>

 

 

 

 

 

 

 

정규식 기초

 

 

 

 

 

 

 

 

 

+) 추가

 

nodemon 패키지

  • 서버측 코드(app.js)가 변경될 때마다 ctrl+c 단축키로 node 명령어를 종료하고 node app.js 명령어를 다시 입력해야 하는 불편함이 있었는데, 이를 해결하기 위해서 사용함
  • 파일들을 모니터링하다가 소스코드 변경시 자동으로 node를 재실행하는 패키지

 

 


참고

 

정규식

https://developer.mozilla.org/ko/docs/Web/JavaScript/Guide/Regular_Expressions

 

 

'웹 백엔드' 카테고리의 다른 글

JSON(JavaScript Object Notation)  (0) 2024.01.29
Node.js - 동적 폼 전송  (1) 2024.01.29
Node.js - 비동기 처리  (1) 2024.01.27
Node.js - Express 모듈과 EJS 템플릿  (1) 2024.01.26
Node.js - API와 HTTP 모듈  (0) 2024.01.25