HTML 강좌 / form의 구조와 GET·POST 제출 방식

form은 사용자가 입력한 값을 제출하는 영역입니다. 양식을 만들 때는 입력 필드의 name, 보낼 주소인 action, 전송 방식인 method를 함께 이해해야 합니다. HTML만으로 입력 화면은 만들 수 있지만, 데이터를 저장하거나 검색하는 기능은 서버 쪽 처리가 필요합니다.

가장 작은 양식 만들기

다음 예제는 검색어를 입력하고 제출하는 양식입니다. 실제 사이트에서 사용하려면 /search를 검색 요청을 처리하는 주소로 바꾸어야 합니다. 필드 이름을 연결하는 for·id와 제출 키인 name의 차이는 label과 input으로 입력 필드 만들기에서 자세히 비교합니다.

<form action="/search" method="get">
  <label for="keyword">검색어</label>
  <input id="keyword" name="q" type="search">
  <button type="submit">검색</button>
</form>

label의 for와 input의 id가 같아 입력칸의 이름을 연결합니다. name="q"는 전송될 값의 이름입니다. 사용자가 ‘HTML’을 입력해 제출하면 GET 요청의 주소에는 일반적으로 ?q=HTML처럼 검색어가 붙습니다. id만 있고 name이 없으면 그 필드의 값은 보통 제출 데이터에 포함되지 않습니다.

action은 요청을 받을 주소이고, method는 그 주소에 값을 전달할 방법입니다. 두 속성을 생략하면 현재 문서 주소로 GET 방식 제출이 기본입니다. 처음 연습할 때는 입력값에 한글과 공백도 넣어 보세요. 주소창에서는 특수문자가 인코딩되어 보일 수 있지만, 그것은 전송을 위한 표기이며 입력 자체가 사라진 것은 아닙니다.

GET과 POST의 차이

method="get"은 양식 데이터를 URL의 쿼리 문자열에 넣습니다. 검색이나 필터처럼 주소를 공유하거나 다시 열기 좋은 요청에 적합합니다. URL에 노출되므로 비밀번호 같은 민감한 값을 보내는 데 사용하지 마세요.

method="post"는 데이터를 요청 본문에 담습니다. 회원가입이나 글 작성처럼 서버의 상태를 바꾸는 작업에 주로 사용합니다. POST라고 해서 데이터가 자동으로 암호화되는 것은 아닙니다. 민감한 값을 다루는 사이트는 HTTPS와 서버 측 처리가 필요합니다.

<form action="/contact" method="post">
  <label for="message">메시지</label>
  <textarea id="message" name="message"></textarea>
  <button type="submit">보내기</button>
</form>

/contact는 설명용 주소입니다. 서버가 없다면 요청 후 오류 응답이 나타날 수 있습니다. 현재 문서로 GET 제출을 시험하려면 앞의 양식에서 action 속성을 제거하세요. 슬래시로 시작하는 주소는 사이트 루트를 기준으로 하므로 로컬 파일에서는 그대로 동작하는 서버 경로가 아닙니다. 주소가 다른 연습용 서버에 실제 개인정보를 보내지 마세요.

특히 action="/search"처럼 슬래시로 시작하는 경로는 사이트의 루트를 기준으로 합니다. 로컬 파일에서 그대로 사용하면 기대한 검색 페이지가 열리지 않습니다. 제출 화면과 실제 처리 기능을 구별하고, 서버가 준비되기 전에는 더미 주소에 개인정보를 보내지 마세요. 파일 업로드 양식은 POST와 별도의 전송 인코딩이 필요하므로 이 예제에 파일 필드만 추가해서는 완성되지 않습니다.

서버로 보내기 전에 데이터 목록 확인하기

다음 전체 코드를 inspect-form.html로 저장하세요. action을 생략하면 현재 문서 주소가 목적지가 됩니다. 명시적으로 적는 action은 비어 있지 않은 유효한 URL이어야 하므로, 현재 주소를 뜻하게 하려고 action=""을 쓰는 대신 속성을 생략합니다.

<!doctype html>
<html lang="ko">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>제출 데이터 실습</title>
</head>
<body>
  <h1>제출 항목 확인</h1>
  <form id="inspect-form" method="get">
    <p><label for="query">검색어</label>
      <input id="query" name="q" value="HTML" required></p>
    <p><label for="limit">최대 개수</label>
      <input id="limit" name="limit" value="5" readonly></p>
    <p><label for="coupon">사용 불가 쿠폰</label>
      <input id="coupon" name="coupon" value="DEMO" disabled></p>
    <p><label><input type="checkbox" name="news" value="yes" checked> 소식 받기</label></p>
    <button type="submit">주소에서 값 확인</button>
  </form>
</body>
</html>

파일을 연 뒤 개발자 도구의 Console에 아래 한 줄을 실행하면 입력 항목의 현재 이름과 값을 봅니다. FormData는 양식의 데이터 목록을 만드는 웹 API이며, 이 명령 자체는 네트워크로 보내거나 입력값 검사를 실행하지 않습니다.

Array.from(new FormData(document.getElementById("inspect-form")).entries())
[["q", "HTML"], ["limit", "5"], ["news", "yes"]]

초기 상태에서는 읽기 전용 limit는 포함되고 비활성 coupon은 빠집니다. 소식 받기 체크를 해제하면 news도 빠집니다. 검색어를 지우고 목록을 만들면 q의 빈 값은 보이지만, 제출 버튼을 누르면 required가 빈 값 제출을 막습니다. 데이터 구성과 제출 검사가 다른 단계임을 비교하세요.

요청 방식 Network에서 확인할 것 결과 판단
GET 요청 URL·method와 쿼리 매개변수 이름과 값이 URL에 인코딩되어 붙음
POST 요청 URL·method와 요청 본문의 Form Data 응답 오류와 데이터 전송은 구분해야 함

실제 서버에서 제공되는 페이지에서는 Network를 연 상태로 제출하고 해당 요청을 선택해 확인하세요. 로컬 file:// 실행은 HTTP 서버의 GET·POST 요청과 다를 수 있습니다. 서버의 404나 405 응답은 목적지나 허용 방식의 문제일 수 있으며, 이를 피하려고 양식의 이름·검증 속성을 지우면 원인을 놓치게 됩니다.

HTML 표준의 제출 속성 · MDN FormData 생성자

전송되지 않는 필드 확인하기

disabled가 붙은 입력 필드는 사용자가 수정할 수 없고 제출 데이터에도 들어가지 않습니다. 단순히 수정을 막으면서 값이 필요한 경우에는 필드 유형에 맞는 readonly 지원 여부를 확인해야 합니다. 체크박스나 라디오 버튼은 선택된 항목만 전송됩니다. 제출 전에 막히는 값의 조건은 입력값 검증: required, 길이·범위 제한, 오류 안내에서 별도로 시험합니다.

개발자 도구의 Network 패널에서 제출 요청의 주소와 전송 데이터를 확인할 수 있습니다. 서버의 응답이 실패하더라도 HTML 필드 이름과 요청 방식이 맞는지 먼저 검사하면 문제 범위를 좁힐 수 있습니다. 정확한 동작은 MDN form 요소 문서를 참고하세요.

제출 결과가 예상과 다르면 다음 순서로 확인하세요. 첫째, 필드마다 name이 있는지 봅니다. 둘째, 선택형 필드가 실제로 선택되었는지 확인합니다. 셋째, 요청 주소와 방식이 서버가 받는 규칙과 맞는지 살펴봅니다. HTML에서 올바른 요청이 나가더라도 서버가 그 값을 저장하거나 응답하는지는 별개의 문제입니다.